#------------------------------------------------------------------------------- # Implementation of the Active Record Pattern #------------------------------------------------------------------------------- require 'sqlite3' DataBase = SQLite3::Database.new("students.db") class Student # Assumes that the database contains a table created the following way: # # create table students ( # id integer primary key autoincrement, # name text, # gpa real # ); attr_reader :id attr_accessor :name, :gpa def initialize(name='', gpa=0) @name = name @gpa = gpa @id = -1 end def save if @id == -1 id = DataBase.get_first_value('select max(id) from students') if id @id = id + 1 else @id = 1 end end DataBase.execute('insert or replace into students values (?, ?, ?)', [@id, @name, @gpa]) end def self.create(name, gpa) student = Student.new(name, gpa) student.save student end def remove if @id != -1 DataBase.execute('delete from students where id = ?', [@id]) @id = -1 end end def self.read(id) row = DataBase.get_first_row('select * from students where id = ?', [id]) if row student = Student.new(row[1], row[2]) student.instance_variable_set(:@id, row[0]) student else nil end end def self.read_all DataBase.execute('select * from students').map do |row| student = Student.new(row[1], row[2]) student.instance_variable_set(:@id, row[0]) student end end def inspect "Student(id: #{ @id}, name: '#{ @name }', gpa: #{ @gpa })" end end #-------------------------------------------------------------------- # Typical use cases # Initialize and save students s1 = Student.new s1.name = 'John' s1.gpa = 3.5 s1.save s2 = Student.new('Mary', 2.7) s2.save # Create a student in one step s3 = Student.create('Peter', 3.1) # Update student with id = 1 s4 = Student.read(1) s4.gpa = 3.9 s4.save # Delete student with id = 2 s5 = Student.read(2) s5.remove # Retrieve all students in an array a = Student.read_all p a