Skip to content

Commit a817edc

Browse files
committed
色々試してる
1 parent da6b072 commit a817edc

File tree

5 files changed

+127
-23
lines changed

5 files changed

+127
-23
lines changed

lib/active_record/connection_adapters/duckdb/database_statements.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module ActiveRecord
44
module ConnectionAdapters
55
module Duckdb
6-
module DatabaseStatements
6+
module DatabaseStatements # :nodoc:
77
def write_query?(sql) # :nodoc:
88
false
99
end
@@ -13,13 +13,25 @@ def execute(sql, name = nil) # :nodoc:
1313

1414
log(sql, name) do
1515
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
16-
p sql
1716
@connection.query(sql)
1817
end
1918
end
2019
end
20+
21+
def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
22+
result = execute_and_clear(sql, name, binds, prepare: prepare, async: async)
23+
24+
# TODO: https://github.com/suketa/ruby-duckdb/issues/168
25+
# build_result(columns: result.columns, rows: result.to_a)
26+
build_result(columns: ['id'], rows: result.to_a)
27+
end
28+
29+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
30+
result = execute_and_clear(sql, name, binds)
31+
result.rows_changed
32+
end
33+
alias :exec_update :exec_delete
2134
end
2235
end
2336
end
2437
end
25-
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveRecord
4+
module ConnectionAdapters
5+
module Duckdb
6+
module SchemaStatements # :nodoc:
7+
private
8+
def new_column_from_field(table_name, field)
9+
_cid, name, type, notnull, _dflt_value, _pk = field
10+
11+
Column.new(
12+
name,
13+
nil, # default value
14+
fetch_type_metadata(type),
15+
!notnull,
16+
nil, # default function
17+
)
18+
end
19+
20+
def data_source_sql(name = nil, type: nil)
21+
scope = quoted_scope(name, type: type)
22+
23+
sql = +"SELECT table_name FROM information_schema.tables"
24+
sql << " WHERE table_schema = '#{scope[:schema]}'"
25+
if scope[:type] || scope[:name]
26+
conditions = []
27+
conditions << "table_type = '#{scope[:type]}'" if scope[:type]
28+
conditions << "table_name = '#{scope[:name]}'" if scope[:name]
29+
sql << " WHERE #{conditions.join(" AND ")}"
30+
end
31+
sql
32+
end
33+
34+
def quoted_scope(name = nil, type: nil)
35+
schema, name = extract_schema_qualified_name(name)
36+
scope = {}
37+
scope[:schema] = schema ? quote(schema) : "main"
38+
scope[:name] = quote(name) if name
39+
scope[:type] = quote(type) if type
40+
scope
41+
end
42+
43+
def extract_schema_qualified_name(string)
44+
schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
45+
schema, name = nil, schema unless name
46+
[schema, name]
47+
end
48+
end
49+
end
50+
end
51+
end
52+

lib/active_record/connection_adapters/duckdb_adapter.rb

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22

33
require 'active_record'
44
require 'active_record/base'
5-
# require 'active_support/dependencies/autoload'
6-
# require 'active_support/callbacks'
7-
# require 'active_support/core_ext/string'
85
require 'active_record/connection_adapters/abstract_adapter'
96
require 'active_record/connection_adapters/duckdb/database_statements'
10-
# require 'active_support/core_ext/kernel'
7+
require 'active_record/connection_adapters/duckdb/schema_statements'
118

129
begin
1310
require 'duckdb'
@@ -29,9 +26,10 @@ class DuckdbAdapter < AbstractAdapter
2926
ADAPTER_NAME = "DuckDB"
3027

3128
include Duckdb::DatabaseStatements
29+
include Duckdb::SchemaStatements
3230

3331
NATIVE_DATABASE_TYPES = {
34-
primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
32+
primary_key: "BIGINT PRIMARY KEY",
3533
string: { name: "varchar" },
3634
text: { name: "text" },
3735
integer: { name: "integer" },
@@ -44,6 +42,45 @@ class DuckdbAdapter < AbstractAdapter
4442
boolean: { name: "boolean" },
4543
json: { name: "json" },
4644
}
45+
46+
def native_database_types
47+
NATIVE_DATABASE_TYPES
48+
end
49+
50+
def primary_keys(table_name) # :nodoc:
51+
raise ArgumentError unless table_name.present?
52+
53+
results = query("PRAGMA table_info(#{table_name})", "SCHEMA")
54+
results.each_with_object([]) do |result, keys|
55+
_cid, name, _type, _notnull, _dflt_value, pk = result
56+
keys << name if pk
57+
end
58+
end
59+
60+
private
61+
def execute_and_clear(sql, name, binds, prepare: false, async: false)
62+
sql = transform_query(sql)
63+
check_if_write_query(sql)
64+
type_casted_binds = type_casted_binds(binds)
65+
66+
log(sql, name, binds, type_casted_binds, async: async) do
67+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
68+
# TODO: prepare の有無でcacheするっぽい?
69+
stmt = DuckDB::PreparedStatement.new(@connection, sql)
70+
if without_prepared_statement?(binds)
71+
@connection.query(sql)
72+
else
73+
@connection.query(sql, *type_casted_binds)
74+
end
75+
end
76+
end
77+
end
78+
79+
def column_definitions(table_name) # :nodoc:
80+
execute("PRAGMA table_info('#{quote_table_name(table_name)}')", "SCHEMA") do |result|
81+
each_hash(result)
82+
end
83+
end
4784
end
4885
end
4986
end

spec/dummy/app/models/post.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,2 @@
11
class Post < ActiveRecord::Base
2-
before_create :set_id
3-
4-
private
5-
6-
def set_id
7-
self.id = SecureRandom.uuid
8-
end
92
end

spec/models/post_spec.rb

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,41 @@
1717
end
1818
end
1919

20-
let(:params) { {title: "duckdb book", views: 10000} }
20+
let(:params) { { id: 1, title: "duckdb book", views: 10000 } }
2121

2222
context 'initialization' do
2323
it 'should initialize a post object with all columns' do
2424
post = Post.new(params)
25-
post.should be_a(Post)
26-
post.title.should eq "duckdb book"
27-
post.views.should eq 10000
25+
expect(post).to be_a(Post)
26+
expect(post.title).to eq "duckdb book"
27+
expect(post.views).to eq 10000
2828
end
2929
end
3030

3131
context 'persistance' do
32-
3332
before do
3433
@post = Post.create!(params)
3534
end
3635

3736
after do
37+
# 多分deleteは数字を返すことを求めてるけど、duckdbのlibraryは削除したentityを返すようになってる
3838
@post.destroy
3939
end
4040

4141
it 'should persist the record to the database' do
42-
@post.persisted?.should eq true
43-
refresh_posts
44-
Post.count.should eq 1
42+
expect(Post.find(1)).to be_a(Post)
43+
expect(Post.count).to eq 1
44+
end
45+
46+
it 'dd' do
47+
post1 = Post.create(params.merge(id: 2))
48+
p post1
49+
p Post.count
50+
51+
d = Post.where(id: [1, 2]).destroy_all
52+
p d
53+
p Post.count
54+
p Post.first
4555
end
4656
end
4757
end

0 commit comments

Comments
 (0)