<commit_before>RSpec.describe ROM::Repository, '#session' do
  subject(:repo) do
    Class.new(ROM::Repository) { relations :users, :posts, :labels }.new(rom)
  end

  include_context 'database'
  include_context 'relations'

  describe 'with :create command' do
    let(:user_changeset) do
      repo.changeset(:users, name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(user_changeset)
      end

      user = repo.users.where(name: 'Jane').one
      expect(user.to_h).to eql(id: 1, name: 'Jane')
    end
  end

  describe 'with :update command' do
    let(:user_changeset) do
      repo.changeset(:users, user.id, user.to_h.merge(name: '<NAME>'))
    end

    let(:user) do
      repo.users.where(name: 'Jane').one
    end

    before do
      repo.command(:create, repo.users).call(name: 'John')
      repo.command(:create, repo.users).call(name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(user_changeset)
      end

      updated_user = repo.users.fetch(user.id)

      expect(updated_user).to eql(id: 2, name: '<NAME>')
    end
  end

  describe 'with :delete command' do
    let(:user) do
      repo.users.where(name: 'Jane').one
    end

    before do
      repo.command(:create, repo.users).call(name: 'John')
      repo.command(:create, repo.users).call(name: 'Jane')
    end

    let(:user_changeset) do
      repo.changeset(delete: repo.users.by_pk(user.id))
    end

    it 'saves data in a transaction' do
      repo.session do |t|
        t.add(user_changeset)
      end

      expect(repo.users.by_pk(user.id).one).to be(nil)
      expect(repo.users.count).to be(1)
    end
  end

  describe 'creating a user with its posts' do
    let(:posts_changeset) do
      repo.changeset(:posts, [{ title: 'Post 1' }, { title: 'Post 2' }])
    end

    let(:user_changeset) do
      repo.changeset(:users, name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(user_changeset.associate(posts_changeset, :author))
      end

      user = repo.users.combine(:posts).one

      expect(user.name).to eql('Jane')
      expect(user.posts.size).to be(2)
      expect(user.posts[0].title).to eql('Post 1')
      expect(user.posts[1].title).to eql('Post 2')
    end
  end

  describe 'creating a user with its posts and their labels' do
    let(:posts_data) do
      [{ title: 'Post 1' }]
    end

    let(:posts_changeset) do
      repo.
        changeset(:posts, posts_data).
        associate(labels_changeset, :posts)
    end

    let(:labels_changeset) do
      repo.changeset(:labels, [{ name: 'red' }, { name: 'green' }])
    end

    let(:user_changeset) do
      repo.
        changeset(:users, name: 'Jane').
        associate(posts_changeset, :author)
    end

    it 'saves data in a transaction' do
      repo.session do |t|
        t.add(user_changeset)
      end

      user = repo.users.combine(posts: [:labels]).one

      expect(user.name).to eql('Jane')
      expect(user.posts.size).to be(1)
      expect(user.posts[0].title).to eql('Post 1')
      expect(user.posts[0].labels.size).to be(2)
      expect(user.posts[0].labels[0].name).to eql('red')
      expect(user.posts[0].labels[1].name).to eql('green')
    end

    context 'with invalid data' do
      let(:posts_data) do
        [{ title: 'Post 1', title: nil }]
      end

      it 'rolls back the transaction' do
        expect {
          repo.session do |t|
            t.add(user_changeset)
          end
        }.to raise_error(ROM::SQL::ConstraintError)

        expect(repo.users.count).to be(0)
        expect(repo.posts.count).to be(0)
        expect(repo.labels.count).to be(0)
      end
    end
  end

  describe 'creating new posts for existing user' do
    let(:posts_changeset) do
      repo.
        changeset(:posts, [{ title: 'Post 1' }, { title: 'Post 2' }]).
        associate(user, :author)
    end

    let(:user) do
      repo.command(:create, repo.users).call(name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(posts_changeset)
      end

      user = repo.users.combine(:posts).one

      expect(user.posts.size).to be(2)
      expect(user.posts[0].title).to eql('Post 1')
      expect(user.posts[1].title).to eql('Post 2')
    end
  end
end
<commit_msg>Add a spec for nested sessions within a transaction<commit_after>RSpec.describe ROM::Repository, '#session' do
  subject(:repo) do
    Class.new(ROM::Repository) { relations :users, :posts, :labels }.new(rom)
  end

  include_context 'database'
  include_context 'relations'

  describe 'with :create command' do
    let(:user_changeset) do
      repo.changeset(:users, name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(user_changeset)
      end

      user = repo.users.where(name: 'Jane').one
      expect(user.to_h).to eql(id: 1, name: 'Jane')
    end
  end

  describe 'with :update command' do
    let(:user_changeset) do
      repo.changeset(:users, user.id, user.to_h.merge(name: '<NAME>'))
    end

    let(:user) do
      repo.users.where(name: 'Jane').one
    end

    before do
      repo.command(:create, repo.users).call(name: 'John')
      repo.command(:create, repo.users).call(name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(user_changeset)
      end

      updated_user = repo.users.fetch(user.id)

      expect(updated_user).to eql(id: 2, name: '<NAME>')
    end
  end

  describe 'with :delete command' do
    let(:user) do
      repo.users.where(name: 'Jane').one
    end

    before do
      repo.command(:create, repo.users).call(name: 'John')
      repo.command(:create, repo.users).call(name: 'Jane')
    end

    let(:user_changeset) do
      repo.changeset(delete: repo.users.by_pk(user.id))
    end

    it 'saves data in a transaction' do
      repo.session do |t|
        t.add(user_changeset)
      end

      expect(repo.users.by_pk(user.id).one).to be(nil)
      expect(repo.users.count).to be(1)
    end
  end

  describe 'creating a user with its posts' do
    let(:posts_changeset) do
      repo.changeset(:posts, [{ title: 'Post 1' }, { title: 'Post 2' }])
    end

    let(:user_changeset) do
      repo.changeset(:users, name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(user_changeset.associate(posts_changeset, :author))
      end

      user = repo.users.combine(:posts).one

      expect(user.name).to eql('Jane')
      expect(user.posts.size).to be(2)
      expect(user.posts[0].title).to eql('Post 1')
      expect(user.posts[1].title).to eql('Post 2')
    end
  end

  describe 'creating a user with its posts and their labels' do
    let(:posts_data) do
      [{ title: 'Post 1' }]
    end

    let(:posts_changeset) do
      repo.
        changeset(:posts, posts_data).
        associate(labels_changeset, :posts)
    end

    let(:labels_changeset) do
      repo.changeset(:labels, [{ name: 'red' }, { name: 'green' }])
    end

    let(:user_changeset) do
      repo.
        changeset(:users, name: 'Jane').
        associate(posts_changeset, :author)
    end

    it 'saves data in a transaction' do
      repo.session do |t|
        t.add(user_changeset)
      end

      user = repo.users.combine(posts: [:labels]).one

      expect(user.name).to eql('Jane')
      expect(user.posts.size).to be(1)
      expect(user.posts[0].title).to eql('Post 1')
      expect(user.posts[0].labels.size).to be(2)
      expect(user.posts[0].labels[0].name).to eql('red')
      expect(user.posts[0].labels[1].name).to eql('green')
    end

    context 'with invalid data' do
      let(:posts_data) do
        [{ title: 'Post 1', title: nil }]
      end

      it 'rolls back the transaction' do
        expect {
          repo.session do |t|
            t.add(user_changeset)
          end
        }.to raise_error(ROM::SQL::ConstraintError)

        expect(repo.users.count).to be(0)
        expect(repo.posts.count).to be(0)
        expect(repo.labels.count).to be(0)
      end
    end
  end

  describe 'creating new posts for existing user' do
    let(:posts_changeset) do
      repo.
        changeset(:posts, [{ title: 'Post 1' }, { title: 'Post 2' }]).
        associate(user, :author)
    end

    let(:user) do
      repo.command(:create, repo.users).call(name: 'Jane')
    end

    it 'saves data in a transaction' do
      repo.session do |s|
        s.add(posts_changeset)
      end

      user = repo.users.combine(:posts).one

      expect(user.posts.size).to be(2)
      expect(user.posts[0].title).to eql('Post 1')
      expect(user.posts[1].title).to eql('Post 2')
    end
  end

  describe 'nesting sessions' do
    let(:user_changeset) do
      repo.changeset(:users, name: 'Jane')
    end

    let(:posts_changeset) do
      repo.changeset(:posts, post_data)
    end

    let(:user) do
      repo.users.where(name: 'Jane').one
    end

    context 'when data is valid' do
      let(:post_data) do
        [{ title: 'Post 1' }, { title: 'Post 2' }]
      end

      it 'saves data in transactions' do
        repo.send(:transaction) do |t|
          repo.session { |s| s.add(user_changeset) }
          repo.session { |s| s.add(posts_changeset.associate(user, :author)) }
        end

        user = repo.users.combine(:posts).one

        expect(user.posts.size).to be(2)
        expect(user.posts[0].title).to eql('Post 1')
        expect(user.posts[1].title).to eql('Post 2')
      end
    end

    context 'when data is not valid' do
      let(:post_data) do
        [{ title: 'Post 1' }, { title: nil }]
      end

      it 'rolls back transaction' do
        expect {
          repo.send(:transaction) do |t|
            repo.session { |s| s.add(user_changeset) }
            repo.session { |s| s.add(posts_changeset.associate(user, :author)) }
          end
        }.to raise_error(ROM::SQL::ConstraintError, /title/)

        expect(repo.users.count).to be(0)
        expect(repo.posts.count).to be(0)
      end
    end
  end
end

{'fraction_non_alphanumeric': 0.13842198932173225, 'fraction_numerical': 0.007118845165117659, 'mean_word_length': 2.4091675092686216, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6702614', 'n_tokens_mistral': 3519, 'n_tokens_neox': 3377, 'n_words': 812}