Skip to content

About

DaJet Script 2.0

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

152 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DaJet Script 2.0 DaJet Metadata at NuGet

Данная версия DaJet Script является продолжением проекта DaJet. В новой версии планируется выполнить рефакторинг существующего кода, сохранив при этом синтаксис и все базовые концепции. Функционал предыдущей версии постепенно переносится в этот репозиторий. Одной из причин является необходимость перевода проекта DaJet на новую версию библиотеки DaJet.Metadata, которая была перписана с нуля.

На данный момент DaJet Script 2.0 уже используется, и вполне успешно, в новых проектах DaJet MCP Server и DaJet Http Server, а также DaJet Studio.

В текущей версии поддерживаются следующие команды:

  • DECLARE или PRIVATE (объявление переменных)
  • SET (присваивание значений переменным)
  • USE (открытие соединения с базой данных)
  • SELECT (с поддержкой общих табличных выражений)
  • INSERT (вставка одной записи)
  • CONSUME (деструктивное чтение из базы данных)
  • PRINT (вывод сообщения в консоль приложения)
  • RETURN (возрат значений из скрипта по WEB API)
  • IF, FOR, WHILE, BREAK, CONTINUE (условия и циклы)
  • TRY, THROW (обработка и вызов исключений)
  • ERROR_MESSAGE (функция получения описания об ошибке)
  • SLEEP (приостановка потока выполнения)
  • JSON (функция сериализации)

Поддерживается работа с базами данных SQL Server и PostgreSQL.

Для выполнения скриптов необходимо подключить в свой проект NuGet-пакет DaJet.Interpreter.

> dotnet add package DaJet.Interpreter --version 1.0.20

Рекомендуется подключение NuGet-пакета DaJet.Host с поддержкой функций хостинга скриптов:

  • обслуживание скриптов из каталога публикации, включая вложенные каталоги;
  • режим хоста "только чтение" (разрешает выполнять только SELECT);
  • кэширование скриптов при первом к ним обращении;
  • автоматическая загрузка скриптов при старте хоста;
  • автоматическое обновление кэша скриптов при их добавлении/изменении без перезагрузки хоста;
  • получение статуса долго выполняемых скриптов;
  • программная отмена выполнения долгих скриптов;
  • контроль выполнения единственного экземпляра скрипта (singleton).
> dotnet add package DaJet.Host --version 1.0.13

Этот пакет имеет следующие зависимости:

  • DaJet.Host (текущий репозиторий)
    • DaJet.Interpreter (текущий репозиторий)
      • DaJet.Scripting (текущий репозиторий)
        • DaJet.Metadata
          • DaJet.FileLogger
          • DaJet.TypeSystem
          • DaJet.Data
            • Npgsql
            • Microsoft.Data.SqlClient

Пример использования интерпретатора DaJet Script 2.0

Файл скрипта DaJet Script test.djs

DECLARE @КодТовара string -- Входящий параметр скрипта
PRIVATE @Результат array  -- Результат выполнения скрипта

USE 'MS_TEST'
  SELECT Ссылка, Код, Наименование
    INTO @Результат
    FROM Справочник.Номенклатура
   WHERE Код = @КодТовара
END

RETURN @Результат -- или JSON(@Результат)

Код программы на C#

private static readonly JsonSerializerOptions JsonOptions = new()
{
    WriteIndented = true,
    ReferenceHandler = ReferenceHandler.IgnoreCycles,
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
};

static void Main()
{
  JsonOptions.Converters.Add(new DictionaryJsonConverter());

  string MS_TEST = "Data Source=server;Initial Catalog=database;Integrated Security=True;Encrypt=False;";

  MetadataProvider.Add("MS_TEST", DataSourceType.SqlServer, in MS_TEST);

  string filePath = Path.Combine(AppContext.BaseDirectory, "scripts", "test.djs");

  Script script = new ScriptBuilder().FromFile(in filePath).Build();

  Interpreter interpreter = new(in script);

  Dictionary<string, object> parameters = new()
  {
    { "КодТовара", "00000002" }
  };

  object value = interpreter.Execute(in parameters);

  string json = JsonSerializer.Serialize(value, value.GetType(), JsonOptions);

  Console.WriteLine(json);
}

Пример использования хоста DaJet Script 2.0

Предполагается, что в корневом каталоге установки хоста DaJet имеется каталог публикации скриптов scripts, в котором уже опубликован скрипт long-task-test.djs. Ниже следующий скрипт демонстрирует в том числе использование специальных директив выполнения скрипта. Скрипт запускается при старте хоста DaJet, является долгим (выделяется отдельный поток операционной системы), а также в каждый момент времени выполняется единственный экземпляр этого скрипта.

Код скрипта DaJet long-task-test.djs

# STARTUP                    -- Запуск скрипта при старте хоста DaJet
# LONG_TASK                  -- Долгий скрипт (отдельный поток выполнения)
# SINGLETON 'LONG TASK TEST' -- Директива контроля единственного выполнения

PRIVATE @Счётчик integer

PRINT '[LONG TASK TEST] START'

WHILE @Счётчик < 10

  SET @Счётчик = @Счётчик + 1

  IF @Счётчик = 5 THEN BREAK END

  PRINT 'LOOP: ' + @Счётчик

  SLEEP 3

END

PRINT '[LONG TASK TEST] END'
private static readonly JsonSerializerOptions JsonOptions = new()
{
    WriteIndented = true,
    ReferenceHandler = ReferenceHandler.IgnoreCycles,
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
};

private static DaJetHost _host;
private static System.Timers.Timer _heartbeat;

static void Main()
{
  JsonOptions.Converters.Add(new EntityJsonConverter());
  JsonOptions.Converters.Add(new DataTypeJsonConverter());
  JsonOptions.Converters.Add(new DataObjectJsonConverter());
  JsonOptions.Converters.Add(new JsonStringEnumConverter());

  string MS_TEST = "Data Source=server;Initial Catalog=database;Integrated Security=True;Encrypt=False;";

  MetadataProvider.Add("MS_TEST", DataSourceType.SqlServer, in MS_TEST);

  _host = DaJetHost.Create("scripts").Run();

  Heartbeat(); // Периодически мониторим состояние долгих скриптов

  // Этот запуск упадёт с ошибкой, так как этот скрипт запускается при старте хоста как singleton
  _ = host.RunAsync("long-task-test.djs").ContinueWith(ShowAsyncResult);

  Console.WriteLine("Press any key to exit the program ...");

  _ = Console.ReadKey(true);
}

private static void ShowAsyncResult(Task<object> task)
{
    if (task.IsCompletedSuccessfully)
    {
        object value = task.Result;

        if (value is not null)
        {
            string json = JsonSerializer.Serialize(value, value.GetType(), JsonOptions);

            Console.WriteLine($"Task [{task.Id}] return value:");
            Console.WriteLine(json);
        }
        else
        {
            Console.WriteLine($"Task [{task.Id}] returned null value.");
        }
    }
    else if (task.IsCanceled)
    {
        Console.WriteLine($"Task [{task.Id}] is canceled.");
    }
    else
    {
        Exception error = task.Exception.Flatten().InnerException;

        Console.WriteLine($"Task [{task.Id}] is faulted: {error.Message}");
    }
}

private static void Heartbeat()
{
    System.Timers.Timer timer = new();

    if (Interlocked.CompareExchange(ref _heartbeat, timer, null) is not null)
    {
        timer.Dispose();
    }
    else
    {
        _heartbeat.AutoReset = true;
        _heartbeat.Elapsed += ShowRunningTasks;
        _heartbeat.Interval = TimeSpan.FromSeconds(1).TotalMilliseconds;
    }

    _heartbeat.Start();
}

private static void ShowRunningTasks(object sender, ElapsedEventArgs args)
{
    foreach (RunningTaskStatus status in _host.GetRunningTasks())
    {
        Console.WriteLine(status.ToString());
    }
}

Результат выполнения программы (консольный вывод)

[LONG TASK TEST] START
LOOP: 1
Press any key to exit the program ...
Task [32] is faulted: Duplicate singleton run: [long-task-test.djs] {LONG TASK TEST}
[28] {Running} long-task-test.djs "LONG TASK TEST"
LOOP: 2
[28] {Running} long-task-test.djs "LONG TASK TEST"
[28] {Running} long-task-test.djs "LONG TASK TEST"
[28] {Running} long-task-test.djs "LONG TASK TEST"
LOOP: 3
[28] {Running} long-task-test.djs "LONG TASK TEST"
[28] {Running} long-task-test.djs "LONG TASK TEST"
[28] {Running} long-task-test.djs "LONG TASK TEST"
LOOP: 4
[28] {Running} long-task-test.djs "LONG TASK TEST"
[28] {Running} long-task-test.djs "LONG TASK TEST"
[28] {Running} long-task-test.djs "LONG TASK TEST"
[LONG TASK TEST] END

About

DaJet Script 2.0

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages