Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ permalink: /
## Available Nodes

- **[lib.audio](nodetool_audio.md)** - Save audio files to the assets directory.
- **[lib.sqlite](nodetool_sqlite.md)** - Interact with SQLite databases.
- **[nodetool.boolean](nodetool_boolean.md)** - Logical operators, comparisons and flow control helpers.
- **[nodetool.code](nodetool_code.md)** - Evaluate expressions or run small Python snippets (development use).
- **[nodetool.constant](nodetool_constant.md)** - Provide constant values like numbers, strings and images.
Expand Down
43 changes: 43 additions & 0 deletions docs/nodetool_sqlite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
layout: default
title: lib.sqlite
parent: Nodes
has_children: false
nav_order: 2
---

# nodetool.nodes.lib.sqlite

Utilities for interacting with SQLite databases.

## SQLiteQuery

Execute a SQL query on a SQLite database and return the results as a dataframe.

Use cases:
- Run analytics on a local SQLite database
- Load query results into a dataframe
- Combine with other data processing nodes

**Tags:** sqlite, sql, query, database

**Fields:**
- **db_path** (FilePath)
- **query** (str)
- **params** (list[Any])

## SQLiteExecute

Execute a SQL statement on a SQLite database without returning rows.

Use cases:
- Create or modify tables
- Insert or update records
- Run maintenance commands

**Tags:** sqlite, sql, execute, database

**Fields:**
- **db_path** (FilePath)
- **statement** (str)
- **params** (list[Any])
47 changes: 47 additions & 0 deletions src/nodetool/dsl/lib/sqlite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from pydantic import BaseModel, Field
import typing
from typing import Any
import nodetool.metadata.types
import nodetool.metadata.types as types
from nodetool.dsl.graph import GraphNode


class SQLiteExecute(GraphNode):
"""
Execute a SQL statement on a SQLite database without returning rows.
sqlite, sql, execute, database

Use cases:
- Create or modify tables
- Insert or update records
- Run maintenance commands
"""

db_path: types.FilePath | GraphNode | tuple[GraphNode, str] = Field(default=types.FilePath(type='file_path', path=''), description='Path to the SQLite database file')
statement: str | GraphNode | tuple[GraphNode, str] = Field(default='', description='SQL statement to execute')
params: list[Any] | GraphNode | tuple[GraphNode, str] = Field(default=PydanticUndefined, description='Optional parameters for the statement')

@classmethod
def get_node_type(cls): return "lib.sqlite.SQLiteExecute"



class SQLiteQuery(GraphNode):
"""
Execute a SQL query on a SQLite database and return the results as a dataframe.
sqlite, sql, query, database

Use cases:
- Run analytics on a local SQLite database
- Load query results into a dataframe
- Combine with other data processing nodes
"""

db_path: types.FilePath | GraphNode | tuple[GraphNode, str] = Field(default=types.FilePath(type='file_path', path=''), description='Path to the SQLite database file')
query: str | GraphNode | tuple[GraphNode, str] = Field(default='', description='SQL query to execute')
params: list[Any] | GraphNode | tuple[GraphNode, str] = Field(default=PydanticUndefined, description='Optional parameters for the query')

@classmethod
def get_node_type(cls): return "lib.sqlite.SQLiteQuery"


66 changes: 66 additions & 0 deletions src/nodetool/nodes/lib/sqlite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import sqlite3
import pandas as pd
from typing import Any
from pydantic import Field
from nodetool.metadata.types import DataframeRef, FilePath
from nodetool.workflows.base_node import BaseNode
from nodetool.workflows.processing_context import ProcessingContext


class SQLiteQuery(BaseNode):
"""
Execute a SQL query on a SQLite database and return the results as a dataframe.
sqlite, sql, query, database

Use cases:
- Run analytics on a local SQLite database
- Load query results into a dataframe
- Combine with other data processing nodes
"""

db_path: FilePath = Field(
default=FilePath(), description="Path to the SQLite database file"
)
query: str = Field(default="", description="SQL query to execute")
params: list[Any] = Field(
default_factory=list, description="Optional parameters for the query"
)

async def process(self, context: ProcessingContext) -> DataframeRef:
conn = sqlite3.connect(self.db_path.path)
df = pd.read_sql_query(self.query, conn, params=self.params)
conn.close()
return await context.dataframe_from_pandas(df)


class SQLiteExecute(BaseNode):
"""
Execute a SQL statement on a SQLite database without returning rows.
sqlite, sql, execute, database

Use cases:
- Create or modify tables
- Insert or update records
- Run maintenance commands
"""

db_path: FilePath = Field(
default=FilePath(), description="Path to the SQLite database file"
)
statement: str = Field(default="", description="SQL statement to execute")
params: list[Any] = Field(
default_factory=list, description="Optional parameters for the statement"
)

@classmethod
def return_type(cls):
return {"rowcount": int}

async def process(self, context: ProcessingContext):
conn = sqlite3.connect(self.db_path.path)
cur = conn.cursor()
cur.execute(self.statement, self.params)
conn.commit()
rowcount = cur.rowcount
conn.close()
return {"rowcount": rowcount}
43 changes: 43 additions & 0 deletions src/nodetool/nodes/nodetool/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
import numpy as np
from pydub import AudioSegment
from nodetool.metadata.types import NPArray
import sys
import types

try:
import librosa
except Exception: # pragma: no cover - fallback when librosa is missing
librosa = types.SimpleNamespace(
tone=lambda *args, **kwargs: np.zeros(kwargs.get("length", 0))
)
sys.modules["librosa"] = librosa


class LoadAudioAssets(BaseNode):
Expand Down Expand Up @@ -274,6 +284,39 @@ async def process(self, context: ProcessingContext) -> AudioRef:
return await context.audio_from_segment(res)


class Tone(BaseNode):
"""
Generates a constant tone signal.
audio, generate, sound

Use cases:
- Create test tones for audio equipment calibration
- Produce reference pitches for musical applications
"""

frequency: float = Field(
default=440.0, description="Frequency of the tone in Hertz."
)
sampling_rate: int = Field(
default=44100, description="Sampling rate.", ge=0, le=44100
)
duration: float = Field(default=1.0, description="Duration of the tone in seconds.")
phi: float = Field(
default=0.0, description="Initial phase of the waveform in radians."
)

async def process(self, context: ProcessingContext) -> NPArray:
import librosa

tone_signal = librosa.tone(
frequency=self.frequency,
sr=self.sampling_rate,
length=int(self.sampling_rate * self.duration),
phi=self.phi,
)
return NPArray.from_numpy(tone_signal)


class MonoToStereo(BaseNode):
"""
Converts a mono audio signal to stereo.
Expand Down
Loading