umbot-ydb-adapter 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -181,7 +181,7 @@ Yandex Lockbox.
181
181
  | `SoundTokens` | `soundToken` | `idx_platform_path` по `(platform, path)` |
182
182
 
183
183
  Все колонки — `Utf8`, колонки ключа — `NOT NULL`. Индексы синхронные (`GLOBAL SYNC`): токен, сохранённый через
184
- `UPSERT`, сразу находится поиском по пути. YDB использует вторичный индекс только при явном `VIEW`, поэтому адаптер
184
+ `INSERT`, сразу находится поиском по пути. YDB использует вторичный индекс только при явном `VIEW`, поэтому адаптер
185
185
  сам добавляет `VIEW idx_platform_path` в поиск токена по `(platform, path)`.
186
186
 
187
187
  Если таблица уже есть, адаптер добавляет недостающие колонки и индексы, но не меняет и не удаляет существующие.
@@ -210,6 +210,10 @@ new YdbAdapter({
210
210
  Типы колонок: `Utf8`, `Int64`, `Double`, `Bool`. Значения приводятся к типу колонки: число `42` в колонке `Utf8`
211
211
  запишется строкой `'42'`.
212
212
 
213
+ Таблицы можно описать и общей для всех адаптеров опцией umbot `appConfig.dbTables` (umbot 3.1.6+): адаптер создаст
214
+ их так же, но все колонки получат тип `Utf8` — в `IDbTableSchema` есть только строковые поля. Если таблица с тем же
215
+ именем есть и в `tables`, используется описание из `tables`.
216
+
213
217
  Для таблиц, не описанных в `tables` (созданных миграцией или вручную), тип значения берётся из правил модели
214
218
  (`rules()`), а если правила нет — из самого значения:
215
219
 
@@ -255,8 +259,10 @@ const stats = await new UsersData(appContext).query(async (sql) => {
255
259
 
256
260
  ## Поведение и ограничения
257
261
 
258
- - **Вставка — `UPSERT`.** Повторная запись с тем же ключом перезаписывает строку, поэтому SDK может безопасно
259
- повторить запрос после временной ошибки сети.
262
+ - **Вставка — `INSERT`.** `add()` с занятым ключом возвращает `false` и не перезаписывает запись, как у SQL-адаптеров;
263
+ для изменения записи используйте `update()` или `save()`. SDK повторяет вставку после временной ошибки сети: если
264
+ первая попытка всё же записала строку, повтор получит «ключ занят», и `add()` вернёт `false` (с ошибкой в логе),
265
+ хотя запись сохранена.
260
266
  - **Запись — в Serializable-транзакции**: так YDB требует для таблиц со вторичными индексами.
261
267
  - **`UPDATE` не меняет колонки ключа**: YDB этого не позволяет, а модель umbot передаёт `platform` и в данных, и в
262
268
  условии.
@@ -119,7 +119,7 @@ export declare class YdbAdapter extends BaseDbAdapter<IYdbDbInfo> {
119
119
  * Сначала выполняется один запрос-проверка (`SELECT ... LIMIT 0` по всем таблицам и индексам).
120
120
  * Если схема уже готова — на этом всё: в Cloud Functions метод вызывается на каждом холодном
121
121
  * старте, и DDL на каждый старт стоил бы заметного времени.
122
- * @param tables Описание таблиц (`DB_TABLES_SCHEMA`)
122
+ * @param tables Описание таблиц от umbot: `DB_TABLES_SCHEMA` и `appConfig.dbTables`
123
123
  * @returns true, если схема готова
124
124
  */
125
125
  ensureSchema(tables: readonly IDbTableSchema[]): Promise<boolean>;
@@ -135,10 +135,11 @@ export declare class YdbAdapter extends BaseDbAdapter<IYdbDbInfo> {
135
135
  */
136
136
  _select(selectData: IQuery, where: IQueryData | null, isOne: boolean): Promise<IModelRes>;
137
137
  /**
138
- * Добавляет запись (UPSERT): повторная запись с тем же ключом перезаписывает строку,
139
- * поэтому SDK может безопасно повторить запрос после временной ошибки сети.
138
+ * Добавляет запись (INSERT). Занятый ключ YDB отклоняет — вернётся false, запись не
139
+ * перезаписывается (как у SQL-адаптеров). SDK повторяет запрос после временной ошибки сети;
140
+ * если первая попытка всё же записала строку, повтор получит «ключ занят» и вернёт false.
140
141
  * @param insertData Запрос с данными в `data`
141
- * @returns true при успехе
142
+ * @returns true при успехе, false — ключ занят или ошибка базы (в логе)
142
143
  */
143
144
  _insert(insertData: IQuery): Promise<boolean>;
144
145
  /**
@@ -157,13 +157,19 @@ class YdbAdapter extends plugins_1.BaseDbAdapter {
157
157
  * Сначала выполняется один запрос-проверка (`SELECT ... LIMIT 0` по всем таблицам и индексам).
158
158
  * Если схема уже готова — на этом всё: в Cloud Functions метод вызывается на каждом холодном
159
159
  * старте, и DDL на каждый старт стоил бы заметного времени.
160
- * @param tables Описание таблиц (`DB_TABLES_SCHEMA`)
160
+ * @param tables Описание таблиц от umbot: `DB_TABLES_SCHEMA` и `appConfig.dbTables`
161
161
  * @returns true, если схема готова
162
162
  */
163
163
  async ensureSchema(tables) {
164
164
  let infos;
165
165
  try {
166
- infos = [...tables.map(yql_1.tableInfoFromSchema), ...this.#customTables()];
166
+ // Одноимённая таблица из опции tables (с типами колонок) заменяет описание от umbot
167
+ // (appConfig.dbTables, все колонки Utf8) — иначе таблица создалась бы с колонками Utf8.
168
+ const byName = new Map();
169
+ for (const info of [...tables.map(yql_1.tableInfoFromSchema), ...this.#customTables()]) {
170
+ byName.set(info.tableName, info);
171
+ }
172
+ infos = [...byName.values()];
167
173
  }
168
174
  catch (error) {
169
175
  this._saveLog('ensureSchema: некорректное описание таблицы', error);
@@ -291,14 +297,15 @@ class YdbAdapter extends plugins_1.BaseDbAdapter {
291
297
  }
292
298
  }
293
299
  /**
294
- * Добавляет запись (UPSERT): повторная запись с тем же ключом перезаписывает строку,
295
- * поэтому SDK может безопасно повторить запрос после временной ошибки сети.
300
+ * Добавляет запись (INSERT). Занятый ключ YDB отклоняет — вернётся false, запись не
301
+ * перезаписывается (как у SQL-адаптеров). SDK повторяет запрос после временной ошибки сети;
302
+ * если первая попытка всё же записала строку, повтор получит «ключ занят» и вернёт false.
296
303
  * @param insertData Запрос с данными в `data`
297
- * @returns true при успехе
304
+ * @returns true при успехе, false — ключ занят или ошибка базы (в логе)
298
305
  */
299
306
  async _insert(insertData) {
300
307
  try {
301
- const statement = (0, yql_1.buildUpsert)(insertData.tableName, insertData.data ?? {}, this.#context(insertData));
308
+ const statement = (0, yql_1.buildInsert)(insertData.tableName, insertData.data ?? {}, this.#context(insertData));
302
309
  await this.#execute(statement, { write: true });
303
310
  return true;
304
311
  }
package/dist/yql.d.ts CHANGED
@@ -124,14 +124,14 @@ export declare function chooseIndex(table: IYdbTableInfo | undefined, where: IQu
124
124
  */
125
125
  export declare function buildSelect(tableName: string, where: IQueryData | null, isOne: boolean, ctx: IYqlContext): IYqlStatement;
126
126
  /**
127
- * Собирает UPSERT одной записи. Поля со значением undefined пропускаются,
128
- * null записывается как NULL.
127
+ * Собирает INSERT одной записи: занятый ключ YDB отклоняет, запись не перезаписывается.
128
+ * Поля со значением undefined пропускаются, null записывается как NULL.
129
129
  * @param tableName Имя таблицы
130
130
  * @param data Данные записи
131
131
  * @param ctx Контекст запроса
132
132
  * @returns Запрос
133
133
  */
134
- export declare function buildUpsert(tableName: string, data: IQueryData, ctx: IYqlContext): IYqlStatement;
134
+ export declare function buildInsert(tableName: string, data: IQueryData, ctx: IYqlContext): IYqlStatement;
135
135
  /**
136
136
  * Собирает UPDATE. Колонки первичного ключа из SET убираются: YDB не меняет ключ
137
137
  * записи, а модель umbot передаёт `uniqueKeys` и в данных, и в условии.
package/dist/yql.js CHANGED
@@ -7,7 +7,7 @@ exports.quoteTable = quoteTable;
7
7
  exports.quoteColumn = quoteColumn;
8
8
  exports.chooseIndex = chooseIndex;
9
9
  exports.buildSelect = buildSelect;
10
- exports.buildUpsert = buildUpsert;
10
+ exports.buildInsert = buildInsert;
11
11
  exports.buildUpdate = buildUpdate;
12
12
  exports.buildDelete = buildDelete;
13
13
  exports.buildCreateTable = buildCreateTable;
@@ -397,14 +397,14 @@ function buildSelect(tableName, where, isOne, ctx) {
397
397
  return { text, params: params.params };
398
398
  }
399
399
  /**
400
- * Собирает UPSERT одной записи. Поля со значением undefined пропускаются,
401
- * null записывается как NULL.
400
+ * Собирает INSERT одной записи: занятый ключ YDB отклоняет, запись не перезаписывается.
401
+ * Поля со значением undefined пропускаются, null записывается как NULL.
402
402
  * @param tableName Имя таблицы
403
403
  * @param data Данные записи
404
404
  * @param ctx Контекст запроса
405
405
  * @returns Запрос
406
406
  */
407
- function buildUpsert(tableName, data, ctx) {
407
+ function buildInsert(tableName, data, ctx) {
408
408
  const params = new YqlParams();
409
409
  const columns = [];
410
410
  const values = [];
@@ -424,7 +424,7 @@ function buildUpsert(tableName, data, ctx) {
424
424
  if (!columns.length) {
425
425
  throw new YqlBuildError(`Нет данных для записи в таблицу "${tableName}".`);
426
426
  }
427
- const text = `UPSERT INTO ${quoteTable(tableName)} (${columns.join(', ')}) VALUES (${values.join(', ')})`;
427
+ const text = `INSERT INTO ${quoteTable(tableName)} (${columns.join(', ')}) VALUES (${values.join(', ')})`;
428
428
  return { text, params: params.params };
429
429
  }
430
430
  /**
@@ -478,7 +478,7 @@ function buildDelete(tableName, where, ctx) {
478
478
  }
479
479
  /**
480
480
  * Описание вторичного индекса для CREATE TABLE / ALTER TABLE.
481
- * Индекс синхронный: запись, только что сохранённая через UPSERT, сразу видна в поиске по индексу.
481
+ * Индекс синхронный: запись, только что сохранённая через INSERT или UPDATE, сразу видна в поиске по индексу.
482
482
  */
483
483
  function indexDefinition(index) {
484
484
  return `INDEX ${quoteColumn(index.name)} GLOBAL SYNC ON (${index.fields.map(quoteColumn).join(', ')})`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umbot-ydb-adapter",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "YDB (Yandex Database) adapter for the umbot framework: storage for Alice skills and chat bots in Yandex Cloud Functions without a separate database server.",
5
5
  "keywords": [
6
6
  "umbot",
@@ -15,7 +15,8 @@
15
15
  "database",
16
16
  "db-adapter",
17
17
  "typescript",
18
- "bot-framework"
18
+ "bot-framework",
19
+ "smartapp"
19
20
  ],
20
21
  "author": {
21
22
  "name": "Maxim-M",
@@ -79,7 +80,7 @@
79
80
  "ts-jest": "^29.4.9",
80
81
  "typescript": "^5.9.3",
81
82
  "typescript-eslint": "^8.60.0",
82
- "umbot": "^3.1.4"
83
+ "umbot": "^3.1.6"
83
84
  },
84
85
  "funding": {
85
86
  "type": "individual",