القضبان + بوستجرس + الربط

الصورة

مرحبا اصدقاء ليس سراً أن العمل في مشاريع كبيرة ذات منطق معقد ، لا يصبح Active Record مساعداً ، بل يمثل عبئًا. تخيل أنك بحاجة إلى إنشاء استعلام معقد جدًا لـ PostgreSQL بطريقة أصلية (في لغة SQL فقط) ، حيث يجب أن يكون هناك عدد معين من المتغيرات. ولكن هناك واحد تافه غير سارة في Rails ، وظيفة تنفيذ الاستعلامات الأصلية لا تسمح باستخدام المجلدات المسماة. ولكن هناك حل :) تم اختباره وتنفيذه بنجاح في مشروع باستخدام Rails API 5.2 + Ruby 2.6.0 + Postgres 11.

لذلك ، أكثر قليلا عن المشكلة. الطريقة الرئيسية التي تسمح لك بتنفيذ استعلامات SQL الخاصة بك هي exec_query:

sql = 'SELECT id, name, desc FROM schema.news WHERE id=$1' bindings = [[nil, 100]] new = ActiveRecord::Base.connection.exec_query(sql, 'SQL', bindings).first 

يوضح المثال أعلاه أن تكوين المجلدات يحدث ، بعبارة ملطفة ، من خلال مكان واحد ، عندما نحاول الحصول على الأخبار تحت الرقم 100 من قاعدة البيانات. لا يمكن تسمية الروابط ، ولكن يتم ترقيمها فقط. وهذا يعقد إلى حد كبير قراءة ودعم الاستعلامات الأصلية. بدلاً من ذلك ، يمكنك استخدام استدعاء الأسلوب find_by_sql لفئة الطراز:

 sql = 'SELECT id, name, desc FROM schema.news WHERE id=:id' new = New.find_by_sql([sql, id: 100]).first 

كل شيء أكثر متعة ومفهومة هنا. لكن السؤال هو ، هذا مقبول أو أكثر إذا كنت تريد تنفيذ طلب بسيط. ولكن إذا كان الطلب معقدًا بالفعل ، فإن تشغيله من خلال النموذج و Active Record نفسه يمثل خسارة كبيرة في السرعة (ببطء) والأداء (يستهلك موارد الخادم). لماذا لا توجد مجلدات مسماة عند العمل مع الاستعلامات الأصلية يعد لغزًا بالنسبة لي ، ولكن هناك حلًا - اكتب برنامج التغليف الصغير الخاص بي ، والذي يمكنه العمل مع المجلدات المُسماة بكل بساطة ، وهو ما قمت به.

أحمل رمز الفئة الساكنة:

 # Class for work with SQL query. # Can use clean SQL with hash bindings. # Convert JSON fields to hash. # Can use if not need get model object! class SqlQuery # Create sql query with hash bindings # # @param [String] sql SQL query # @param [Hash] bind bindings data for query # # @return [Array] executed SQL request data and return array with hashes def self.execute(sql, bind = {}) bindings = [] bind_index = 1 # Get all bindings if exist unless bind.empty? bind.each do |key, value| # Change name bind to $ bind sql.gsub!(/(?<!:):#{key}(?=\b)/, "$#{bind_index}") bind_index += 1 # Add new bind data bindings << [nil, value] end end # Execute query, convert to hash with symbol keys result = ActiveRecord::Base.connection.exec_query(sql, 'SQL', bindings).map(&:symbolize_keys) # Convert JSON data to hash result.map do |v| next if v.nil? v.each do |key, val| v[key] = json_to_hash(val) end end end # Convert JSON to hash if correct data # # @param [String] json string # @return [Hash] return hash if json is correct or input data def self.json_to_hash(json) JSON.parse(json, symbolize_names: true) rescue json end end 

كما ترون من الكود ، كل شيء بسيط مثل ركن المنزل. يعمل الاستعلام مثل هذا:

 sql = 'SELECT id, name, desc FROM schema.news WHERE id=:id' binding = { id: 100 } new = SqlQuery.execute(sql, binding).first 

الإخراج هو دائما مجرد تجزئة. شرح قليلا. تأخذ طريقة التنفيذ سلسلة استعلام وتجزئة مع المجلدات. من الواضح أن الارتباطات الموجودة في الطلب والتجزئة يجب أن تتطابق. بعد ذلك ، نقوم بالتجول بين التجزئات مع المجلدات واستبدالها بمتغيرات مرقمة من النموذج $ 1 ، $ 2 ، وما إلى ذلك في الطلب نفسه ، وإنشاء مجموعة من القيم المرقمة في نفس الوقت ، حيث يكون العنصر الأول للصفيف هو $ 1 ، والثاني هو $ 2 ، وهكذا. ثم ننفذ الاستعلام باستخدام طريقة exec_query القياسية ، ونعمل من خلال الاستجابة مع المخطط ونحول المفاتيح الموجودة في التجزئة إلى أحرف. بعد ذلك ، يتم تشغيل المخطط مرة أخرى وفقًا للإجابة ، حيث نتحقق من كل قيمة حقل لمحتوى JSON فيها. إذا كان هناك JSON وكان صالحًا ، فقم بتحويله إلى تجزئة تحتوي على مفاتيح ورموز ، وإذا لم يكن الحقل هو JSON ، فقم بإلقاء استثناء نعيد فيه القيمة. هذا كل شيء.

كما ترون ، ليس من المنطقي وضع المئات من جميع أنواع الأحجار الكريمة ، وتبديد الأداء العام ، من أجل الحصول على النتيجة المرجوة. يمكنك كتابة العديد من القرارات اللازمة بسرعة كبيرة بنفسك ، بعد أن قضيت ما لا يقل عن الوقت والكود.

روابط إلى جيثب وقطع الجواهر مع البرنامج المساعد:
github.com/kirill-dan/active_sql_bindings
rubygems.org/gems/active_sql_bindings

حظا سعيدا للجميع ، أراك قريبا.

طبع من بلوق الخاص بك. الأصل هنا

Source: https://habr.com/ru/post/ar438110/


All Articles