Class: Tina4::DocStore::SqliteCollection

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/docstore.rb

Overview

A SQLite-backed collection exposing the everyday Mongo API.

Instance Method Summary collapse

Constructor Details

#initialize(conn, name) ⇒ SqliteCollection

Returns a new instance of SqliteCollection.

Raises:

  • (ArgumentError)


557
558
559
560
561
562
563
564
565
566
# File 'lib/tina4/docstore.rb', line 557

def initialize(conn, name)
  @connection = conn
  @name = name.to_s
  raise ArgumentError, "DocStore: invalid collection name #{name.inspect}" unless @name.match?(/\A[A-Za-z_][A-Za-z0-9_]*\z/)

  @quoted_name = "\"#{@name}\""
  @connection.execute(
    "CREATE TABLE IF NOT EXISTS #{@quoted_name} (_id TEXT PRIMARY KEY, doc TEXT NOT NULL)"
  )
end

Instance Method Details

#count_documents(filter = nil) ⇒ Object



610
611
612
613
614
# File 'lib/tina4/docstore.rb', line 610

def count_documents(filter = nil)
  where, params = DocStore.compile_filter(filter || {})
  row = @connection.execute("SELECT count(*) AS c FROM #{@quoted_name} WHERE #{where}", params).first
  scalar(row).to_i
end

#delete_many(filter) ⇒ Object



687
688
689
690
691
692
# File 'lib/tina4/docstore.rb', line 687

def delete_many(filter)
  where, params = DocStore.compile_filter(filter || {})
  before = count_documents(filter)
  @connection.execute("DELETE FROM #{@quoted_name} WHERE #{where}", params)
  DeleteResult.new(before)
end

#delete_one(filter) ⇒ Object

-- deletes --



679
680
681
682
683
684
685
# File 'lib/tina4/docstore.rb', line 679

def delete_one(filter)
  rows = matching_rows(filter, limit: 1)
  return DeleteResult.new(0) if rows.empty?

  @connection.execute("DELETE FROM #{@quoted_name} WHERE _id = ?", [rows.first.first])
  DeleteResult.new(1)
end

#distinct(key, filter = nil) ⇒ Object



621
622
623
624
625
626
627
628
# File 'lib/tina4/docstore.rb', line 621

def distinct(key, filter = nil)
  seen = []
  find(filter).each do |doc|
    v = doc[key.to_s]
    seen << v unless seen.include?(v)
  end
  seen
end

#dropObject



694
695
696
# File 'lib/tina4/docstore.rb', line 694

def drop
  @connection.execute("DROP TABLE IF EXISTS #{@quoted_name}")
end

#estimated_document_countObject



616
617
618
619
# File 'lib/tina4/docstore.rb', line 616

def estimated_document_count
  row = @connection.execute("SELECT count(*) AS c FROM #{@quoted_name}").first
  scalar(row).to_i
end

#find(filter = nil, projection = nil) ⇒ Object

-- reads --



594
595
596
597
# File 'lib/tina4/docstore.rb', line 594

def find(filter = nil, projection = nil)
  where, params = DocStore.compile_filter(filter || {})
  Cursor.new(@connection, @quoted_name, where, params, projection)
end

#find_one(filter = nil, projection = nil) ⇒ Object

The uniform Tina4 spelling, ADDITIVE to find(filter).first (ADR-0035).

Mongo::Collection has no find_one, which is why ADR-0025 corollary 1 deleted this. ADR-0035 amends the means, not the goal: MongoCollection supplies find_one on the driver side, so the method now exists with the same meaning on BOTH halves of the swap. The signature is pymongo's, which is what the Python master already ships.



606
607
608
# File 'lib/tina4/docstore.rb', line 606

def find_one(filter = nil, projection = nil)
  find(filter, projection).first
end

#insert_many(documents) ⇒ Object



579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/tina4/docstore.rb', line 579

def insert_many(documents)
  ids = []
  documents.each do |document|
    doc = stringify(document)
    doc["_id"] = ObjectId.new unless doc.key?("_id")
    ids << doc["_id"]
    @connection.execute(
      "INSERT INTO #{@quoted_name} (_id, doc) VALUES (?, ?)",
      [DocStore.id_key(doc["_id"]), DocStore.dump_doc(doc)]
    )
  end
  InsertManyResult.new(ids)
end

#insert_one(document) ⇒ Object

-- writes --



569
570
571
572
573
574
575
576
577
# File 'lib/tina4/docstore.rb', line 569

def insert_one(document)
  doc = stringify(document)
  doc["_id"] = ObjectId.new unless doc.key?("_id")
  @connection.execute(
    "INSERT INTO #{@quoted_name} (_id, doc) VALUES (?, ?)",
    [DocStore.id_key(doc["_id"]), DocStore.dump_doc(doc)]
  )
  InsertOneResult.new(doc["_id"])
end

#replace_one(filter, replacement, upsert: false) ⇒ Object



660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
# File 'lib/tina4/docstore.rb', line 660

def replace_one(filter, replacement, upsert: false)
  rows = matching_rows(filter, limit: 1)
  if rows.empty?
    if upsert
      doc = stringify(replacement)
      doc["_id"] = ObjectId.new unless doc.key?("_id")
      insert_one(doc)
      return UpdateResult.new(0, 0, doc["_id"])
    end
    return UpdateResult.new(0, 0, nil)
  end
  old_id, doc_text = rows.first
  doc = stringify(replacement)
  doc["_id"] = DocStore.decode_value(JSON.parse(doc_text))["_id"] unless doc.key?("_id")
  write_back(old_id, doc)
  UpdateResult.new(1, 1, nil)
end

#update_many(filter, update, upsert: false) ⇒ Object



645
646
647
648
649
650
651
652
653
654
655
656
657
658
# File 'lib/tina4/docstore.rb', line 645

def update_many(filter, update, upsert: false)
  rows = matching_rows(filter)
  return do_upsert(filter, update) if rows.empty? && upsert

  matched = 0
  modified = 0
  rows.each do |old_id, doc_text|
    matched += 1
    doc = DocStore.decode_value(JSON.parse(doc_text))
    new_doc = DocStore.apply_update(doc, update)
    modified += 1 if write_back(old_id, new_doc)
  end
  UpdateResult.new(matched, modified, nil)
end

#update_one(filter, update, upsert: false) ⇒ Object

-- updates (filter pushed to SQL; mutation applied per matched doc) --



631
632
633
634
635
636
637
638
639
640
641
642
643
# File 'lib/tina4/docstore.rb', line 631

def update_one(filter, update, upsert: false)
  rows = matching_rows(filter, limit: 1)
  if rows.empty?
    return do_upsert(filter, update) if upsert

    return UpdateResult.new(0, 0, nil)
  end
  old_id, doc_text = rows.first
  doc = DocStore.decode_value(JSON.parse(doc_text))
  new_doc = DocStore.apply_update(doc, update)
  modified = write_back(old_id, new_doc)
  UpdateResult.new(1, modified ? 1 : 0, nil)
end