parquet 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66a87903cde02fff1e0a91627311bc1eba1fccc1d61915b7504c9fc61e10ed39
4
- data.tar.gz: 3d93f8aa12b664fd0dcff05b98dc3f12ba6ce745507ff18847936dafe8958be4
3
+ metadata.gz: d46e0a95ff244189cadf71b3860b03aaf7638629d8c2eeda2800eaae57c0dbd2
4
+ data.tar.gz: 8bd2a8a29c7b199fcd67f7ababf241ebdcc871a0ff247fbd5320b789a6e6222e
5
5
  SHA512:
6
- metadata.gz: f042ba14e11c51849be30d22df7a1c63911bcf2ca6778b463b53878b562676f151f9a91a376baf57c3819a89861af2b76e58a80b66ea8c38870b8cf18664105a
7
- data.tar.gz: f708de1716e9640bba8fc3537c76b2cfefbcf9db709ea560db619eb6a50ef2a3965d06b43cb127541ae33067f2facab8bf75df6d8fe6c3aea6cadb765d099a2f
6
+ metadata.gz: ae074d37108a5e12369638a23fcf0962ee416ac901dfcb64daf67b43e76e1566f50f56ccc890581a4cee8b14a0b801ad65dd874dd64c4d0882715e94d35e71b6
7
+ data.tar.gz: 9e08475b60bf1a5ee5e296aecca6df33a9f13fbe747914eadc45b171b6745feda099a3f8b4a1bca57ce3b3fdb03d4452545170d44d4dc90a4168c7b9194d8c19
data/Cargo.lock CHANGED
@@ -743,12 +743,70 @@ dependencies = [
743
743
  "either",
744
744
  ]
745
745
 
746
+ [[package]]
747
+ name = "itertools"
748
+ version = "0.14.0"
749
+ source = "registry+https://github.com/rust-lang/crates.io-index"
750
+ checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
751
+ dependencies = [
752
+ "either",
753
+ ]
754
+
746
755
  [[package]]
747
756
  name = "itoa"
748
757
  version = "1.0.14"
749
758
  source = "registry+https://github.com/rust-lang/crates.io-index"
750
759
  checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
751
760
 
761
+ [[package]]
762
+ name = "jemalloc-sys"
763
+ version = "0.5.4+5.3.0-patched"
764
+ source = "registry+https://github.com/rust-lang/crates.io-index"
765
+ checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2"
766
+ dependencies = [
767
+ "cc",
768
+ "libc",
769
+ ]
770
+
771
+ [[package]]
772
+ name = "jemallocator"
773
+ version = "0.5.4"
774
+ source = "registry+https://github.com/rust-lang/crates.io-index"
775
+ checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc"
776
+ dependencies = [
777
+ "jemalloc-sys",
778
+ "libc",
779
+ ]
780
+
781
+ [[package]]
782
+ name = "jiff"
783
+ version = "0.1.19"
784
+ source = "registry+https://github.com/rust-lang/crates.io-index"
785
+ checksum = "943611a469f78ab9afdac9022e473a80fca16a9deca6c5be3eb566d872231e76"
786
+ dependencies = [
787
+ "jiff-tzdb-platform",
788
+ "log",
789
+ "portable-atomic",
790
+ "portable-atomic-util",
791
+ "serde",
792
+ "windows-sys",
793
+ ]
794
+
795
+ [[package]]
796
+ name = "jiff-tzdb"
797
+ version = "0.1.1"
798
+ source = "registry+https://github.com/rust-lang/crates.io-index"
799
+ checksum = "91335e575850c5c4c673b9bd467b0e025f164ca59d0564f69d0c2ee0ffad4653"
800
+
801
+ [[package]]
802
+ name = "jiff-tzdb-platform"
803
+ version = "0.1.1"
804
+ source = "registry+https://github.com/rust-lang/crates.io-index"
805
+ checksum = "9835f0060a626fe59f160437bc725491a6af23133ea906500027d1bd2f8f4329"
806
+ dependencies = [
807
+ "jiff-tzdb",
808
+ ]
809
+
752
810
  [[package]]
753
811
  name = "jobserver"
754
812
  version = "0.1.32"
@@ -876,6 +934,16 @@ version = "0.2.11"
876
934
  source = "registry+https://github.com/rust-lang/crates.io-index"
877
935
  checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
878
936
 
937
+ [[package]]
938
+ name = "libmimalloc-sys"
939
+ version = "0.1.39"
940
+ source = "registry+https://github.com/rust-lang/crates.io-index"
941
+ checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44"
942
+ dependencies = [
943
+ "cc",
944
+ "libc",
945
+ ]
946
+
879
947
  [[package]]
880
948
  name = "litemap"
881
949
  version = "0.7.4"
@@ -948,6 +1016,15 @@ version = "2.7.4"
948
1016
  source = "registry+https://github.com/rust-lang/crates.io-index"
949
1017
  checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
950
1018
 
1019
+ [[package]]
1020
+ name = "mimalloc"
1021
+ version = "0.1.43"
1022
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1023
+ checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633"
1024
+ dependencies = [
1025
+ "libmimalloc-sys",
1026
+ ]
1027
+
951
1028
  [[package]]
952
1029
  name = "minimal-lexical"
953
1030
  version = "0.2.1"
@@ -1119,15 +1196,21 @@ dependencies = [
1119
1196
  name = "parquet"
1120
1197
  version = "0.1.0"
1121
1198
  dependencies = [
1199
+ "ahash",
1200
+ "arrow-array",
1201
+ "arrow-schema",
1122
1202
  "bytes",
1203
+ "itertools 0.14.0",
1204
+ "jemallocator",
1205
+ "jiff",
1123
1206
  "kanal",
1124
1207
  "magnus 0.7.1",
1208
+ "mimalloc",
1125
1209
  "parquet 54.0.0",
1126
1210
  "rb-sys",
1127
1211
  "serde",
1128
1212
  "serde_magnus",
1129
1213
  "thiserror",
1130
- "xxhash-rust",
1131
1214
  ]
1132
1215
 
1133
1216
  [[package]]
@@ -1197,6 +1280,21 @@ version = "0.3.31"
1197
1280
  source = "registry+https://github.com/rust-lang/crates.io-index"
1198
1281
  checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
1199
1282
 
1283
+ [[package]]
1284
+ name = "portable-atomic"
1285
+ version = "1.10.0"
1286
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1287
+ checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
1288
+
1289
+ [[package]]
1290
+ name = "portable-atomic-util"
1291
+ version = "0.2.4"
1292
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1293
+ checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
1294
+ dependencies = [
1295
+ "portable-atomic",
1296
+ ]
1297
+
1200
1298
  [[package]]
1201
1299
  name = "proc-macro2"
1202
1300
  version = "1.0.92"
@@ -1796,12 +1894,6 @@ version = "0.5.5"
1796
1894
  source = "registry+https://github.com/rust-lang/crates.io-index"
1797
1895
  checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
1798
1896
 
1799
- [[package]]
1800
- name = "xxhash-rust"
1801
- version = "0.8.14"
1802
- source = "registry+https://github.com/rust-lang/crates.io-index"
1803
- checksum = "d7d48f1b18be023c95e7b75f481cac649d74be7c507ff4a407c55cfb957f7934"
1804
-
1805
1897
  [[package]]
1806
1898
  name = "yoke"
1807
1899
  version = "0.7.5"
data/Gemfile CHANGED
@@ -6,7 +6,12 @@ gem "rake"
6
6
  # Use local version of parquet
7
7
  gemspec
8
8
 
9
- group :development, :test do
10
- gem "minitest", "~> 5.0"
9
+ group :development do
11
10
  gem "benchmark-ips", "~> 2.12"
11
+ # gem "polars-df"
12
+ gem "duckdb"
13
+ end
14
+
15
+ group :test do
16
+ gem "minitest", "~> 5.0"
12
17
  end
data/README.md CHANGED
@@ -8,22 +8,78 @@ At the moment, it only supports iterating rows as either a hash or an array.
8
8
 
9
9
  ## Usage
10
10
 
11
+ This library provides high-level bindings to parquet-rs with two primary APIs for reading Parquet files: row-wise and column-wise iteration. The column-wise API generally offers better performance, especially when working with subset of columns.
12
+
13
+ ### Row-wise Iteration
14
+
15
+ The `each_row` method provides sequential access to individual rows:
16
+
11
17
  ```ruby
12
18
  require "parquet"
13
19
 
14
- # Read each row as a hash
15
- Parquet.each_row("test/data.parquet") { |row| puts row.inspect }
20
+ # Basic usage with default hash output
21
+ Parquet.each_row("data.parquet") do |row|
22
+ puts row.inspect # {"id"=>1, "name"=>"name_1"}
23
+ end
16
24
 
17
- # Read each row as an array
18
- Parquet.each_row("test/data.parquet", result_type: :array) { |row| puts row.inspect }
25
+ # Array output for more efficient memory usage
26
+ Parquet.each_row("data.parquet", result_type: :array) do |row|
27
+ puts row.inspect # [1, "name_1"]
28
+ end
19
29
 
20
- # Read from an IO object (like File or StringIO)
21
- File.open("test/data.parquet", "rb") do |file|
22
- Parquet.each_row(file) { |row| puts row.inspect }
30
+ # Select specific columns to reduce I/O
31
+ Parquet.each_row("data.parquet", columns: ["id", "name"]) do |row|
32
+ puts row.inspect
23
33
  end
24
34
 
25
- # Or with StringIO
26
- io = StringIO.new(File.binread("test/data.parquet"))
27
- Parquet.each_row(io) { |row| puts row.inspect }
35
+ # Reading from IO objects
36
+ File.open("data.parquet", "rb") do |file|
37
+ Parquet.each_row(file) do |row|
38
+ puts row.inspect
39
+ end
40
+ end
41
+ ```
42
+
43
+ ### Column-wise Iteration
44
+
45
+ The `each_column` method reads data in column-oriented batches, which is typically more efficient for analytical queries:
28
46
 
47
+ ```ruby
48
+ require "parquet"
49
+
50
+ # Process columns in batches of 1024 rows
51
+ Parquet.each_column("data.parquet", batch_size: 1024) do |batch|
52
+ # With result_type: :hash (default)
53
+ puts batch.inspect
54
+ # {
55
+ # "id" => [1, 2, ..., 1024],
56
+ # "name" => ["name_1", "name_2", ..., "name_1024"]
57
+ # }
58
+ end
59
+
60
+ # Array output with specific columns
61
+ Parquet.each_column("data.parquet",
62
+ columns: ["id", "name"],
63
+ result_type: :array,
64
+ batch_size: 1024) do |batch|
65
+ puts batch.inspect
66
+ # [
67
+ # [1, 2, ..., 1024], # id column
68
+ # ["name_1", "name_2", ...] # name column
69
+ # ]
70
+ end
29
71
  ```
72
+
73
+ ### Arguments
74
+
75
+ Both methods accept these common arguments:
76
+
77
+ - `input`: Path string or IO-like object containing Parquet data
78
+ - `result_type`: Output format (`:hash` or `:array`, defaults to `:hash`)
79
+ - `columns`: Optional array of column names to read (improves performance)
80
+
81
+ Additional arguments for `each_column`:
82
+
83
+ - `batch_size`: Number of rows per batch (defaults to implementation-defined value)
84
+
85
+ When no block is given, both methods return an Enumerator.
@@ -7,7 +7,10 @@ edition = "2021"
7
7
  crate-type = ["cdylib"]
8
8
 
9
9
  [dependencies]
10
+ ahash = "0.8"
10
11
  parquet = { version = "^54.0", features = ["json", "object_store"] }
12
+ arrow-schema = "54.0.0"
13
+ arrow-array = "54.0.0"
11
14
  bytes = "^1.9"
12
15
  kanal = "0.1.0-pre8"
13
16
  magnus = { version = "0.7", features = ["rb-sys"] }
@@ -15,4 +18,12 @@ rb-sys = "^0.9"
15
18
  serde = { version = "1.0", features = ["derive"] }
16
19
  serde_magnus = "0.8.1"
17
20
  thiserror = "2.0"
18
- xxhash-rust = { version = "0.8.12", features = ["xxh3"] }
21
+ itertools = "^0.14"
22
+ jiff = "0.1.19"
23
+
24
+
25
+ [target.'cfg(target_os = "linux")'.dependencies]
26
+ jemallocator = { version = "0.5", features = ["disable_initial_exec_tls"] }
27
+
28
+ [target.'cfg(not(any(target_os = "linux", target_os = "windows")))'.dependencies]
29
+ mimalloc = { version = "0.1", default-features = false }
@@ -0,0 +1,13 @@
1
+ #[cfg(target_os = "linux")]
2
+ use jemallocator::Jemalloc;
3
+
4
+ #[cfg(not(any(target_os = "linux", target_os = "windows")))]
5
+ use mimalloc::MiMalloc;
6
+
7
+ #[global_allocator]
8
+ #[cfg(target_os = "linux")]
9
+ static ALLOC: Jemalloc = Jemalloc;
10
+
11
+ #[global_allocator]
12
+ #[cfg(not(any(target_os = "linux", target_os = "windows")))]
13
+ static ALLOC: MiMalloc = MiMalloc;
@@ -0,0 +1,54 @@
1
+ use ahash::RandomState;
2
+ use magnus::{
3
+ block::Yield, value::ReprValue, Error as MagnusError, KwArgs, RArray, RHash, Symbol, Value,
4
+ };
5
+
6
+ use crate::{ColumnRecord, RowRecord};
7
+
8
+ pub struct RowEnumeratorArgs {
9
+ pub rb_self: Value,
10
+ pub to_read: Value,
11
+ pub result_type: String,
12
+ pub columns: Option<Vec<String>>,
13
+ }
14
+
15
+ #[inline]
16
+ pub fn create_row_enumerator(
17
+ args: RowEnumeratorArgs,
18
+ ) -> Result<Yield<Box<dyn Iterator<Item = RowRecord<RandomState>>>>, MagnusError> {
19
+ let kwargs = RHash::new();
20
+ kwargs.aset(Symbol::new("result_type"), Symbol::new(args.result_type))?;
21
+ if let Some(columns) = args.columns {
22
+ kwargs.aset(Symbol::new("columns"), RArray::from_vec(columns))?;
23
+ }
24
+ let enumerator = args
25
+ .rb_self
26
+ .enumeratorize("each_row", (args.to_read, KwArgs(kwargs)));
27
+ Ok(Yield::Enumerator(enumerator))
28
+ }
29
+
30
+ pub struct ColumnEnumeratorArgs {
31
+ pub rb_self: Value,
32
+ pub to_read: Value,
33
+ pub result_type: String,
34
+ pub columns: Option<Vec<String>>,
35
+ pub batch_size: Option<usize>,
36
+ }
37
+
38
+ #[inline]
39
+ pub fn create_column_enumerator(
40
+ args: ColumnEnumeratorArgs,
41
+ ) -> Result<Yield<Box<dyn Iterator<Item = ColumnRecord<RandomState>>>>, MagnusError> {
42
+ let kwargs = RHash::new();
43
+ kwargs.aset(Symbol::new("result_type"), Symbol::new(args.result_type))?;
44
+ if let Some(columns) = args.columns {
45
+ kwargs.aset(Symbol::new("columns"), RArray::from_vec(columns))?;
46
+ }
47
+ if let Some(batch_size) = args.batch_size {
48
+ kwargs.aset(Symbol::new("batch_size"), batch_size)?;
49
+ }
50
+ let enumerator = args
51
+ .rb_self
52
+ .enumeratorize("each_column", (args.to_read, KwArgs(kwargs)));
53
+ Ok(Yield::Enumerator(enumerator))
54
+ }
@@ -6,8 +6,14 @@
6
6
  /// so this optimization could be removed if any issues arise.
7
7
  use std::{
8
8
  collections::HashMap,
9
- sync::{atomic::AtomicU32, LazyLock, Mutex},
9
+ sync::{
10
+ atomic::{AtomicU32, Ordering},
11
+ LazyLock, Mutex, OnceLock,
12
+ },
10
13
  };
14
+
15
+ use magnus::{r_string::FString, value::Opaque, IntoValue, RString, Ruby, Value};
16
+
11
17
  use thiserror::Error;
12
18
 
13
19
  #[derive(Debug, Error)]
@@ -16,66 +22,139 @@ pub enum CacheError {
16
22
  LockError(String),
17
23
  }
18
24
 
19
- static STRING_CACHE: LazyLock<Mutex<HashMap<&'static str, AtomicU32>>> =
25
+ static STRING_CACHE: LazyLock<Mutex<HashMap<&'static str, (StringCacheKey, AtomicU32)>>> =
20
26
  LazyLock::new(|| Mutex::new(HashMap::with_capacity(100)));
21
27
 
22
28
  pub struct StringCache;
23
29
 
30
+ #[derive(Copy, Clone)]
31
+ pub struct StringCacheKey(Opaque<FString>, &'static str);
32
+
33
+ impl StringCacheKey {
34
+ pub fn new(string: &str) -> Self {
35
+ let rstr = RString::new(string);
36
+ let fstr = rstr.to_interned_str();
37
+ Self(Opaque::from(fstr), fstr.as_str().unwrap())
38
+ }
39
+ }
40
+
41
+ impl AsRef<str> for StringCacheKey {
42
+ fn as_ref(&self) -> &'static str {
43
+ self.1
44
+ }
45
+ }
46
+
47
+ impl IntoValue for StringCacheKey {
48
+ fn into_value_with(self, handle: &Ruby) -> Value {
49
+ handle.into_value(self.0)
50
+ }
51
+ }
52
+
53
+ impl std::fmt::Debug for StringCacheKey {
54
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55
+ self.1.fmt(f)
56
+ }
57
+ }
58
+
59
+ impl PartialEq for StringCacheKey {
60
+ fn eq(&self, other: &Self) -> bool {
61
+ self.1 == other.1
62
+ }
63
+ }
64
+
65
+ impl std::cmp::Eq for StringCacheKey {}
66
+
67
+ impl std::hash::Hash for StringCacheKey {
68
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
69
+ self.1.hash(state);
70
+ }
71
+ }
72
+
24
73
  impl StringCache {
25
74
  #[allow(dead_code)]
26
- pub fn intern(string: String) -> Result<&'static str, CacheError> {
75
+ pub fn intern(string: String) -> Result<StringCacheKey, CacheError> {
27
76
  let mut cache = STRING_CACHE
28
77
  .lock()
29
78
  .map_err(|e| CacheError::LockError(e.to_string()))?;
30
79
 
31
- if let Some((&existing, count)) = cache.get_key_value(string.as_str()) {
32
- count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
33
- Ok(existing)
80
+ if let Some((_, (interned_string, counter))) = cache.get_key_value(string.as_str()) {
81
+ counter.fetch_add(1, Ordering::Relaxed);
82
+ Ok(*interned_string)
34
83
  } else {
84
+ let interned = StringCacheKey::new(string.as_str());
35
85
  let leaked = Box::leak(string.into_boxed_str());
36
- cache.insert(leaked, AtomicU32::new(1));
37
- Ok(leaked)
86
+ cache.insert(leaked, (interned, AtomicU32::new(1)));
87
+ Ok(interned)
38
88
  }
39
89
  }
40
90
 
41
- pub fn intern_many(strings: &[String]) -> Result<Vec<&'static str>, CacheError> {
91
+ pub fn intern_many(strings: &[String]) -> Result<Vec<StringCacheKey>, CacheError> {
42
92
  let mut cache = STRING_CACHE
43
93
  .lock()
44
94
  .map_err(|e| CacheError::LockError(e.to_string()))?;
45
95
 
46
- let mut result = Vec::with_capacity(strings.len());
96
+ let mut result: Vec<StringCacheKey> = Vec::with_capacity(strings.len());
47
97
  for string in strings {
48
- if let Some((&existing, count)) = cache.get_key_value(string.as_str()) {
49
- count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
50
- result.push(existing);
98
+ if let Some((_, (interned_string, counter))) = cache.get_key_value(string.as_str()) {
99
+ counter.fetch_add(1, Ordering::Relaxed);
100
+ result.push(*interned_string);
51
101
  } else {
102
+ let interned = StringCacheKey::new(&string);
52
103
  let leaked = Box::leak(string.clone().into_boxed_str());
53
- cache.insert(leaked, AtomicU32::new(1));
54
- result.push(leaked);
104
+ cache.insert(leaked, (interned, AtomicU32::new(1)));
105
+ result.push(interned);
55
106
  }
56
107
  }
57
108
  Ok(result)
58
109
  }
59
110
 
60
- pub fn clear(headers: &[&'static str]) -> Result<(), CacheError> {
111
+ pub fn clear(headers: &[StringCacheKey]) -> Result<(), CacheError> {
61
112
  let mut cache = STRING_CACHE
62
113
  .lock()
63
114
  .map_err(|e| CacheError::LockError(e.to_string()))?;
64
115
 
65
- for header in headers {
66
- if let Some(count) = cache.get(header) {
67
- // Returns the previous value of the counter
68
- let was = count.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
69
- if was == 1 {
70
- cache.remove(header);
71
- let ptr = *header as *const str as *mut str;
72
- unsafe {
73
- let _ = Box::from_raw(ptr);
116
+ let to_remove: Vec<_> = headers
117
+ .iter()
118
+ .filter_map(|header| {
119
+ let key = header.as_ref();
120
+ if let Some((_, (_, counter))) = cache.get_key_value(key) {
121
+ let prev_count = counter.fetch_sub(1, Ordering::Relaxed);
122
+ if prev_count == 1 {
123
+ Some(key)
124
+ } else {
125
+ None
74
126
  }
127
+ } else {
128
+ None
75
129
  }
76
- }
130
+ })
131
+ .collect();
132
+
133
+ for key in to_remove {
134
+ cache.remove(key);
77
135
  }
78
136
 
79
137
  Ok(())
80
138
  }
81
139
  }
140
+
141
+ pub struct HeaderCacheCleanupIter<I> {
142
+ pub inner: I,
143
+ pub headers: OnceLock<Vec<StringCacheKey>>,
144
+ }
145
+
146
+ impl<I: Iterator> Iterator for HeaderCacheCleanupIter<I> {
147
+ type Item = I::Item;
148
+
149
+ fn next(&mut self) -> Option<Self::Item> {
150
+ self.inner.next()
151
+ }
152
+ }
153
+
154
+ impl<I> Drop for HeaderCacheCleanupIter<I> {
155
+ fn drop(&mut self) {
156
+ if let Some(headers) = self.headers.get() {
157
+ StringCache::clear(&headers).unwrap();
158
+ }
159
+ }
160
+ }
@@ -1,9 +1,16 @@
1
+ mod allocator;
2
+ mod enumerator;
1
3
  pub mod header_cache;
2
4
  mod reader;
5
+ mod ruby_integration;
3
6
  mod ruby_reader;
7
+ mod types;
4
8
  mod utils;
5
9
 
10
+ use crate::enumerator::*;
6
11
  use crate::reader::*;
12
+ use crate::ruby_integration::*;
13
+ use crate::types::*;
7
14
 
8
15
  use magnus::{Error, Ruby};
9
16
 
@@ -11,6 +18,7 @@ use magnus::{Error, Ruby};
11
18
  #[magnus::init]
12
19
  fn init(ruby: &Ruby) -> Result<(), Error> {
13
20
  let module = ruby.define_module("Parquet")?;
14
- module.define_module_function("each_row", magnus::method!(parse_parquet, -1))?;
21
+ module.define_module_function("each_row", magnus::method!(parse_parquet_rows, -1))?;
22
+ module.define_module_function("each_column", magnus::method!(parse_parquet_columns, -1))?;
15
23
  Ok(())
16
24
  }