From c1862bc02a3c2176011440557ff46bf485106c62 Mon Sep 17 00:00:00 2001 From: Giallombardo Nathan Date: Thu, 27 Jun 2024 12:39:22 +0000 Subject: [PATCH 1/6] add doc couchbase-orm --- lib/couchbase-orm.rb | 63 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm.rb b/lib/couchbase-orm.rb index f4924679..621234ed 100644 --- a/lib/couchbase-orm.rb +++ b/lib/couchbase-orm.rb @@ -4,10 +4,12 @@ require 'logger' require 'active_support/lazy_load_hooks' +# Add English locale config to load path by default. ActiveSupport.on_load(:i18n) do I18n.load_path << File.expand_path('couchbase-orm/locale/en.yml', __dir__) end +# Top-level module for project. module CouchbaseOrm autoload :Encrypt, 'couchbase-orm/encrypt' autoload :Error, 'couchbase-orm/error' @@ -19,16 +21,37 @@ module CouchbaseOrm autoload :HasMany, 'couchbase-orm/utilities/has_many' autoload :AttributesDynamic, 'couchbase-orm/attributes/dynamic' + # if COUCHBASE_ORM_DEBUG environement variable exist then logger is set to Logger::DEBUG level + # else logger is set to Logger::INFO level + # @return [ Logger ] current logger setted for CouchbaseOrm def self.logger @@logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDOUT).tap { |l| l.level = Logger::INFO unless ENV['COUCHBASE_ORM_DEBUG'] } end + # Allows you to set a logger for CouchbaseOrm, + # which can be usueful for logging messages or errors related to CouchbaseOrm + # @param [ Logger ] logger your custom logger + # + # @example Setting the logger in code + # require 'logger' + # my_logger = Logger.new(STDOUT) + # my_logger.level = Logger::DEBUG + # CouchbaseOrm.logger = my_logger + # + # @return [ Logger ] the new logger setted def self.logger=(logger) @@logger = logger end + # Attempts to load a record or records from the Couchbase database. + # + # This method can handle both single IDs and arrays of IDs. + # It adapts its behavior based on the type and quantity of the input. + # + # @param [String, Array] id The ID or array of IDs of the records to load. + # @return [Object, Array] The loaded model(s). Returns an array of models if the input was an array, or a single model if the input was a single ID. def self.try_load(id) result = nil was_array = id.is_a?(Array) @@ -49,6 +72,14 @@ def self.try_load(id) try_load_create_model(result, id) end + # Creates a model from the fetched data and ID. + # + # This method checks the type of the fetched document and matches it against the design documents of known models. + # If a match is found, it creates and returns an instance of the corresponding model. + # + # @param [Object] result The fetched record data. Expected to have a `content` method that returns a hash. + # @param [String] id The ID of the record. + # @return [Object, nil] The created model if a matching model is found, or `nil` if no match is found or if the document type is not present. def self.try_load_create_model(result, id) ddoc = result&.content&.[]('type') return nil unless ddoc @@ -62,11 +93,41 @@ def self.try_load_create_model(result, id) end end -# Provide Boolean conversion function +# Add method to the Kernel module, making it available in all Ruby objects since Kernel is included by Object. # See: http://www.virtuouscode.com/2012/05/07/a-ruby-conversion-idiom/ module Kernel private + # Converts a given value to a Boolean. + # + # This method attempts to convert different types of values to their boolean equivalents. + # - Strings and Symbols: 'true' (case-insensitive) is converted to true, 'false' (case-insensitive) is converted to false. + # - Integers: 0 is converted to false, non-zero integers are converted to true. + # - `false` and `nil` are converted to false. + # - `true` is converted to true. + # @see http://www.virtuouscode.com/2012/05/07/a-ruby-conversion-idiom/ + # @param [Object] value The value to be converted to a Boolean. + # @return [Boolean] The Boolean representation of the given value. + # @raise [ArgumentError] If the value cannot be converted to a Boolean. + # @example Converting various values to Boolean + # include Kernel + # + # Boolean('true') # => true + # Boolean(' false ') # => false + # Boolean(:true) # => true + # Boolean(:false) # => false + # Boolean(1) # => true + # Boolean(0) # => false + # Boolean(nil) # => false + # Boolean(true) # => true + # Boolean(false) # => false + # + # # Invalid conversion raises ArgumentError + # begin + # Boolean('not a boolean') + # rescue ArgumentError => e + # e.message # => "invalid value for Boolean(): \"not a boolean\"" + # end def Boolean(value) # rubocop:disable Naming/MethodName case value when String, Symbol From d0b644f7193b7d725ca1e9a4b74a31748c08af8a Mon Sep 17 00:00:00 2001 From: Giallombardo Nathan Date: Thu, 27 Jun 2024 15:36:23 +0000 Subject: [PATCH 2/6] delete license --- .../generators/couchbase_orm_generator.rb | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/lib/rails/generators/couchbase_orm_generator.rb b/lib/rails/generators/couchbase_orm_generator.rb index a6163ec3..de9f662c 100644 --- a/lib/rails/generators/couchbase_orm_generator.rb +++ b/lib/rails/generators/couchbase_orm_generator.rb @@ -1,23 +1,3 @@ -# frozen_string_literal: true - -# -# Author:: Couchbase -# Copyright:: 2012 Couchbase, Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - require 'rails/generators/named_base' require 'rails/generators/active_model' From 9685bd5b4840232852ee97fe16e76ae47e40a92c Mon Sep 17 00:00:00 2001 From: Giallombardo Nathan Date: Mon, 1 Jul 2024 15:03:49 +0000 Subject: [PATCH 3/6] add document views --- lib/couchbase-orm/views.rb | 95 +++++++++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 16 deletions(-) diff --git a/lib/couchbase-orm/views.rb b/lib/couchbase-orm/views.rb index 8a2aed4f..dabbf857 100644 --- a/lib/couchbase-orm/views.rb +++ b/lib/couchbase-orm/views.rb @@ -8,20 +8,52 @@ module Views extend ActiveSupport::Concern module ClassMethods - # Defines a view for the model - # - # @param [Symbol, String, Array] names names of the views - # @param [Hash] options options passed to the {Couchbase::View} - # - # @example Define some views for a model - # class Post < CouchbaseOrm::Base - # view :all - # view :by_rating, emit_key: :rating - # end - # - # Post.by_rating do |response| - # # ... - # end + # Defines a Couchbase view with dynamic method creation. + # + # Couchbase views allow you to create custom queries on your data using map and reduce functions. + # They are defined in design documents and can be queried to retrieve documents or aggregated data. + # For more details, see the [Couchbase Views Basics](https://docs.couchbase.com/server/current/learn/views/views-basics.html). + # + # @param name [Symbol, String] The name of the view. + # @param map [String, nil] The map function for the view (optional). + # @param emit_key [Symbol, Array, nil] The key(s) to emit from the map function (optional). + # @param reduce [String, nil] The reduce function for the view (optional). + # @param options [Hash] Additional options for the view query. + # @return [void] + # @raise [ArgumentError] if the class already responds to the given name. + # + # @example Define a simple view to emit documents by `created_at` + # class MyModel + # include CouchbaseOrm::Model + # view :by_created_at, emit_key: :created_at + # end + # + # # You can now use the dynamically defined method: + # results = MyModel.by_created_at + # + # @example Define a view with multiple emit keys + # class MyModel + # include CouchbaseOrm::Model + # view :by_user_and_date, emit_key: [:user_id, :created_at] + # end + # + # # Use the defined view method + # results = MyModel.by_user_and_date + # + # @example Define a view with a custom map function + # class MyModel + # include CouchbaseOrm::Model + # view :by_custom_map, map: <<-MAP + # function (doc) { + # if (doc.type === "my_model") { + # emit(doc.custom_field, null); + # } + # } + # MAP + # end + # + # # Use the defined view method + # results = MyModel.by_custom_map def view(name, map: nil, emit_key: nil, reduce: nil, **options) raise ArgumentError.new("#{self} already respond_to? #{name}") if self.respond_to?(name) @@ -81,8 +113,37 @@ def view(name, map: nil, emit_key: nil, reduce: nil, **options) end ViewDefaults = {include_docs: true}.freeze - # add a view and lookup method to the model for finding all records - # using a value in the supplied attr. + # Sets up a Couchbase view and a corresponding finder method for the given attribute. + # + # Couchbase views allow you to create custom queries on your data using map and reduce functions. + # They are defined in design documents and can be queried to retrieve documents or aggregated data. + # For more details, see the [Couchbase Views Basics](https://docs.couchbase.com/server/current/learn/views/views-basics.html). + # + # @param attr [Symbol] The attribute to create the view and finder method for. + # @param validate [Boolean] Whether to validate the presence of the attribute (default: true). + # @param find_method [Symbol, String, nil] The name of the finder method to be created (optional). + # @param view_method [Symbol, String, nil] The name of the view method to be created (optional). + # @return [void] + # + # @example Define an index view for the `email` attribute + # class User + # include CouchbaseOrm::Model + # index_view :email + # end + # + # # This creates a view method `by_email` and a finder method `find_by_email` + # users_by_email = User.by_email(key: 'user@example.com') + # user = User.find_by_email('user@example.com') + # + # @example Define an index view for the `username` attribute with custom method names + # class User + # include CouchbaseOrm::Model + # index_view :username, find_method: :find_user_by_username, view_method: :by_username_view + # end + # + # # This creates a view method `by_username_view` and a finder method `find_user_by_username` + # users_by_username = User.by_username_view(key: 'john_doe') + # user = User.find_user_by_username('john_doe') def index_view(attr, validate: true, find_method: nil, view_method: nil) view_method ||= "by_#{attr}" find_method ||= "find_#{view_method}" @@ -150,6 +211,8 @@ def ensure_design_document! end end + private + def include_docs(view_result) if view_result.rows.length > 1 self.find(view_result.rows.map(&:id)) From df28d9f4ed128781da11cd3308988879fa17aa9e Mon Sep 17 00:00:00 2001 From: Giallombardo Nathan Date: Mon, 1 Jul 2024 15:16:12 +0000 Subject: [PATCH 4/6] add n1ql documentation --- lib/couchbase-orm/n1ql.rb | 88 ++++++++++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 16 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 6ff78316..83aaec34 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -20,20 +20,46 @@ def self.sanitize(value) end module ClassMethods - # Defines a query N1QL for the model - # - # @param [Symbol, String, Array] names names of the views - # @param [Hash] options options passed to the {Couchbase::N1QL} - # - # @example Define some N1QL queries for a model - # class Post < CouchbaseOrm::Base - # n1ql :by_rating, emit_key: :rating - # end - # - # Post.by_rating do |response| - # # ... - # end - # TODO: add range keys [:startkey, :endkey] + # Defines a N1QL query method with dynamic method creation. + # + # N1QL (Non-first Normal Form Query Language) is a powerful query language for Couchbase + # that allows you to perform complex queries on your data. + # For more details, see the [Couchbase N1QL Documentation](https://docs.couchbase.com/server/current/n1ql/n1ql-intro/index.html). + # + # @param name [Symbol, String] The name of the N1QL query method. + # @param query_fn [Proc, nil] An optional function to customize the query. + # @param emit_key [Symbol, Array] The key(s) to emit from the query (optional, defaults to an empty array). + # @param custom_order [String, nil] An optional parameter to define custom ordering for the query. + # @param options [Hash] Additional options for the N1QL query. + # @return [void] + # @raise [ArgumentError] if the class already responds to the given name. + # + # @example Define a N1QL query to find documents by `email` + # class User + # include CouchbaseOrm::Model + # n1ql :find_by_email, emit_key: :email + # end + # + # # This creates a query method `find_by_email` + # users = User.find_by_email(key: 'user@example.com') + # + # @example Define a N1QL query with custom ordering + # class User + # include CouchbaseOrm::Model + # n1ql :ordered_by_creation, emit_key: :created_at, custom_order: 'ORDER BY created_at DESC' + # end + # + # # This creates a query method `ordered_by_creation` + # users = User.ordered_by_creation + # + # @example Define a N1QL query with a custom query function + # class User + # include CouchbaseOrm::Model + # n1ql :custom_query, query_fn: ->(keys) { "SELECT * FROM `bucket` WHERE #{keys.map { |k| "`#{k}` = ?" }.join(' AND ')}" }, emit_key: [:email, :username] + # end + # + # # This creates a query method `custom_query` + # users = User.custom_query(key: { email: 'user@example.com', username: 'johndoe' }) def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) raise ArgumentError.new("#{self} already respond_to? #{name}") if self.respond_to?(name) @@ -65,8 +91,38 @@ def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) end N1QL_DEFAULTS = { include_docs: true }.freeze - # add a n1ql query and lookup method to the model for finding all records - # using a value in the supplied attr. + # Sets up a Couchbase N1QL query and a corresponding finder method for the given attribute. + # + # N1QL (Non-first Normal Form Query Language) is a powerful query language for Couchbase + # that allows you to perform complex queries on your data. + # For more details, see the [Couchbase N1QL Documentation](https://docs.couchbase.com/server/current/n1ql/n1ql-intro/index.html). + # + # @param attr [Symbol] The attribute to create the N1QL query and finder method for. + # @param validate [Boolean] Whether to validate the presence of the attribute (default: true). + # @param find_method [Symbol, String, nil] The name of the finder method to be created (optional). + # @param n1ql_method [Symbol, String, nil] The name of the N1QL query method to be created (optional). + # @return [void] + # @raise [ArgumentError] if the class already responds to the given name. + # + # @example Define an index N1QL query for the `email` attribute + # class User + # include CouchbaseOrm::Model + # index_n1ql :email + # end + # + # # This creates a N1QL query method `by_email` and a finder method `find_by_email` + # users = User.by_email(key: ['user@example.com']) + # user = User.find_by_email('user@example.com') + # + # @example Define an index N1QL query for the `username` attribute with custom method names + # class User + # include CouchbaseOrm::Model + # index_n1ql :username, find_method: :find_user_by_username, n1ql_method: :by_username_n1ql + # end + # + # # This creates a N1QL query method `by_username_n1ql` and a finder method `find_user_by_username` + # users = User.by_username_n1ql(key: ['john_doe']) + # user = User.find_user_by_username('john_doe') def index_n1ql(attr, validate: true, find_method: nil, n1ql_method: nil) n1ql_method ||= "by_#{attr}" find_method ||= "find_#{n1ql_method}" From 6bf77d4b53893739fe03c6d0e524c5f5471268a1 Mon Sep 17 00:00:00 2001 From: Giallombardo Nathan Date: Mon, 1 Jul 2024 15:19:34 +0000 Subject: [PATCH 5/6] fix rubocop --- lib/couchbase-orm.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm.rb b/lib/couchbase-orm.rb index 621234ed..ebdd9149 100644 --- a/lib/couchbase-orm.rb +++ b/lib/couchbase-orm.rb @@ -30,10 +30,10 @@ def self.logger } end - # Allows you to set a logger for CouchbaseOrm, - # which can be usueful for logging messages or errors related to CouchbaseOrm + # Allows you to set a logger for CouchbaseOrm, + # which can be usueful for logging messages or errors related to CouchbaseOrm # @param [ Logger ] logger your custom logger - # + # # @example Setting the logger in code # require 'logger' # my_logger = Logger.new(STDOUT) @@ -47,7 +47,7 @@ def self.logger=(logger) # Attempts to load a record or records from the Couchbase database. # - # This method can handle both single IDs and arrays of IDs. + # This method can handle both single IDs and arrays of IDs. # It adapts its behavior based on the type and quantity of the input. # # @param [String, Array] id The ID or array of IDs of the records to load. From c24ee418c0ff64b018c9694ed6779211200cdc3c Mon Sep 17 00:00:00 2001 From: Giallombardo Nathan Date: Mon, 1 Jul 2024 15:22:26 +0000 Subject: [PATCH 6/6] fix rubocop --- lib/couchbase-orm.rb | 1 - lib/rails/generators/couchbase_orm_generator.rb | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm.rb b/lib/couchbase-orm.rb index ebdd9149..587bfc5f 100644 --- a/lib/couchbase-orm.rb +++ b/lib/couchbase-orm.rb @@ -1,4 +1,3 @@ -# frozen_string_literal: true, encoding: ASCII-8BIT # frozen_string_literal: true require 'logger' diff --git a/lib/rails/generators/couchbase_orm_generator.rb b/lib/rails/generators/couchbase_orm_generator.rb index de9f662c..7213df5a 100644 --- a/lib/rails/generators/couchbase_orm_generator.rb +++ b/lib/rails/generators/couchbase_orm_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails/generators/named_base' require 'rails/generators/active_model'