1use nu_engine::command_prelude::*;
2use nu_protocol::shell_error::io::IoError;
3use std::{collections::VecDeque, io::Read};
4
5#[cfg(feature = "sqlite")]
6use crate::database::SQLiteQueryBuilder;
7
8#[derive(Clone)]
9pub struct Last;
10
11impl Command for Last {
12 fn name(&self) -> &str {
13 "last"
14 }
15
16 fn signature(&self) -> Signature {
17 Signature::build("last")
18 .input_output_types(vec![
19 (
20 Type::List(Box::new(Type::Any)),
23 Type::Any,
24 ),
25 (Type::Binary, Type::Binary),
26 (Type::Range, Type::Any),
27 ])
28 .optional(
29 "rows",
30 SyntaxShape::Int,
31 "Starting from the back, the number of rows to return.",
32 )
33 .allow_variants_without_examples(true)
34 .switch("strict", "Throw an error if input is empty.", Some('s'))
35 .category(Category::Filters)
36 }
37
38 fn description(&self) -> &str {
39 "Return only the last several rows of the input. Counterpart of `first`. Opposite of `drop`."
40 }
41
42 fn examples(&self) -> Vec<Example<'_>> {
43 vec![
44 Example {
45 example: "[1,2,3] | last 2",
46 description: "Return the last 2 items of a list/table.",
47 result: Some(Value::list(
48 vec![Value::test_int(2), Value::test_int(3)],
49 Span::test_data(),
50 )),
51 },
52 Example {
53 example: "[1,2,3] | last",
54 description: "Return the last item of a list/table.",
55 result: Some(Value::test_int(3)),
56 },
57 Example {
58 example: "0x[01 23 45] | last 2",
59 description: "Return the last 2 bytes of a binary value.",
60 result: Some(Value::binary(vec![0x23, 0x45], Span::test_data())),
61 },
62 Example {
63 example: "1..3 | last",
64 description: "Return the last item of a range.",
65 result: Some(Value::test_int(3)),
66 },
67 ]
68 }
69
70 fn run(
71 &self,
72 engine_state: &EngineState,
73 stack: &mut Stack,
74 call: &Call,
75 input: PipelineData,
76 ) -> Result<PipelineData, ShellError> {
77 let head = call.head;
78 let rows: Option<Spanned<i64>> = call.opt(engine_state, stack, 0)?;
79 let strict_mode = call.has_flag(engine_state, stack, "strict")?;
80
81 let return_single_element = rows.is_none();
84 let rows = if let Some(rows) = rows {
85 if rows.item < 0 {
86 return Err(ShellError::NeedsPositiveValue { span: rows.span });
87 } else {
88 rows.item as usize
89 }
90 } else {
91 1
92 };
93
94 let metadata = input.metadata();
95
96 if rows == 0 {
98 return Ok(Value::list(Vec::new(), head).into_pipeline_data_with_metadata(metadata));
99 }
100
101 match input {
102 PipelineData::ListStream(_, _) | PipelineData::Value(Value::Range { .. }, _) => {
103 let iterator = input.into_iter_strict(head)?;
104
105 let mut buf = VecDeque::new();
107
108 for row in iterator {
109 engine_state.signals().check(&head)?;
110 if buf.len() == rows {
111 buf.pop_front();
112 }
113 buf.push_back(row);
114 }
115
116 if return_single_element {
117 if let Some(last) = buf.pop_back() {
118 Ok(last.into_pipeline_data())
119 } else if strict_mode {
120 Err(ShellError::AccessEmptyContent { span: head })
121 } else {
122 Ok(Value::nothing(head).into_pipeline_data_with_metadata(metadata))
125 }
126 } else {
127 Ok(Value::list(buf.into(), head).into_pipeline_data_with_metadata(metadata))
128 }
129 }
130 PipelineData::Value(val, _) => {
131 let span = val.span();
132 match val {
133 Value::List { mut vals, .. } => {
134 if return_single_element {
135 if let Some(v) = vals.pop() {
136 Ok(v.into_pipeline_data())
137 } else if strict_mode {
138 Err(ShellError::AccessEmptyContent { span: head })
139 } else {
140 Ok(Value::nothing(head).into_pipeline_data_with_metadata(metadata))
143 }
144 } else {
145 let i = vals.len().saturating_sub(rows);
146 vals.drain(..i);
147 Ok(Value::list(vals, span).into_pipeline_data_with_metadata(metadata))
148 }
149 }
150 Value::Binary { mut val, .. } => {
151 if return_single_element {
152 if let Some(val) = val.pop() {
153 Ok(Value::int(val.into(), span).into_pipeline_data())
154 } else if strict_mode {
155 Err(ShellError::AccessEmptyContent { span: head })
156 } else {
157 Ok(Value::nothing(head).into_pipeline_data_with_metadata(metadata))
160 }
161 } else {
162 let i = val.len().saturating_sub(rows);
163 val.drain(..i);
164 Ok(Value::binary(val, span).into_pipeline_data())
165 }
166 }
167 Value::Error { error, .. } => Err(*error),
169 #[cfg(feature = "sqlite")]
170 Value::Custom {
172 val: custom_val,
173 internal_span,
174 ..
175 } => {
176 if let Some(table) =
177 custom_val.as_any().downcast_ref::<SQLiteQueryBuilder>()
178 {
179 if return_single_element {
180 let new_table = table
182 .clone()
183 .with_order_by("rowid DESC".to_string())
184 .with_limit(1);
185 let result = new_table.execute(head)?;
186 let value = result.into_value(head)?;
187 if let Value::List { vals, .. } = value {
188 if let Some(val) = vals.into_iter().next() {
189 Ok(val.into_pipeline_data())
190 } else if strict_mode {
191 Err(ShellError::AccessEmptyContent { span: head })
192 } else {
193 Ok(Value::nothing(head)
196 .into_pipeline_data_with_metadata(metadata))
197 }
198 } else {
199 Err(ShellError::NushellFailed {
200 msg: "Expected list from SQLiteQueryBuilder".into(),
201 })
202 }
203 } else {
204 let new_table = table
206 .clone()
207 .with_order_by("rowid DESC".to_string())
208 .with_limit(rows as i64);
209 let result = new_table.execute(head)?;
210 let value = result.into_value(head)?;
211
212 if let Value::List { mut vals, .. } = value {
213 vals.reverse();
215 Ok(Value::list(vals, head)
216 .into_pipeline_data_with_metadata(metadata))
217 } else {
218 Ok(value.into_pipeline_data_with_metadata(metadata))
219 }
220 }
221 } else {
222 Err(ShellError::OnlySupportsThisInputType {
223 exp_input_type: "list, binary or range".into(),
224 wrong_type: custom_val.type_name(),
225 dst_span: head,
226 src_span: internal_span,
227 })
228 }
229 }
230 other => Err(ShellError::OnlySupportsThisInputType {
231 exp_input_type: "list, binary or range".into(),
232 wrong_type: other.get_type().to_string(),
233 dst_span: head,
234 src_span: other.span(),
235 }),
236 }
237 }
238 PipelineData::ByteStream(stream, ..) => {
239 if stream.type_().is_binary_coercible() {
240 let span = stream.span();
241 if let Some(mut reader) = stream.reader() {
242 const TAKE: u64 = 8192;
245 let mut buf = VecDeque::with_capacity(rows + TAKE as usize);
246 loop {
247 let taken = std::io::copy(&mut (&mut reader).take(TAKE), &mut buf)
248 .map_err(|err| IoError::new(err, span, None))?;
249 if buf.len() > rows {
250 buf.drain(..(buf.len() - rows));
251 }
252 if taken < TAKE {
253 if return_single_element {
255 if !buf.is_empty() {
256 return Ok(
257 Value::int(buf[0] as i64, head).into_pipeline_data()
258 );
259 } else if strict_mode {
260 return Err(ShellError::AccessEmptyContent { span: head });
261 } else {
262 return Ok(Value::nothing(head)
265 .into_pipeline_data_with_metadata(metadata));
266 }
267 } else {
268 return Ok(Value::binary(buf, head).into_pipeline_data());
269 }
270 }
271 }
272 } else {
273 Ok(PipelineData::empty())
274 }
275 } else {
276 Err(ShellError::OnlySupportsThisInputType {
277 exp_input_type: "list, binary or range".into(),
278 wrong_type: stream.type_().describe().into(),
279 dst_span: head,
280 src_span: stream.span(),
281 })
282 }
283 }
284 PipelineData::Empty => Err(ShellError::OnlySupportsThisInputType {
285 exp_input_type: "list, binary or range".into(),
286 wrong_type: "null".into(),
287 dst_span: call.head,
288 src_span: call.head,
289 }),
290 }
291 }
292}
293
294#[cfg(test)]
295mod test {
296 use super::*;
297
298 #[test]
299 fn test_examples() {
300 use crate::test_examples;
301
302 test_examples(Last {})
303 }
304}