@coopenomics/factory 2025.7.1 → 2025.7.2

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/dist/index.cjs CHANGED
@@ -2916,7 +2916,7 @@ class PDFService {
2916
2916
 
2917
2917
  const name = "@coopenomics/factory";
2918
2918
  const type = "module";
2919
- const version = "2025.7.1";
2919
+ const version = "2025.7.2";
2920
2920
  const packageManager = "pnpm@9.0.6";
2921
2921
  const description = "";
2922
2922
  const author = "Alex Ant <chairman.voskhod@gmail.com>";
@@ -2959,14 +2959,15 @@ const scripts = {
2959
2959
  prepublishOnly: "nr build",
2960
2960
  release: "bumpp && npm publish",
2961
2961
  test: "vitest --dir test --testTimeout=240000 --exclude documents --watch=false",
2962
- typecheck: "tsc --noEmit"
2962
+ typecheck: "tsc --noEmit",
2963
+ "setup-indexes": "tsx scripts/setup-indexes.ts"
2963
2964
  };
2964
2965
  const dependencies = {
2965
2966
  ajv: "^8.13.0",
2966
2967
  "ajv-formats": "^3.0.1",
2967
2968
  "ajv-i18n": "^4.2.0",
2968
2969
  axios: "^1.7.2",
2969
- cooptypes: "2025.7.1",
2970
+ cooptypes: "2025.7.2",
2970
2971
  dotenv: "^16.4.5",
2971
2972
  "eosjs-ecc": "^4.0.7",
2972
2973
  handlebars: "^4.7.8",
@@ -3007,7 +3008,7 @@ const pnpm = {
3007
3008
  "vite@>=5.1.0 <=5.1.6": ">=5.1.7"
3008
3009
  }
3009
3010
  };
3010
- const gitHead = "ac8836628eb82672b481dbf86050918f41bf24ca";
3011
+ const gitHead = "305864c1ed125be304a3b4fa9749ac6743dd5571";
3011
3012
  const packageJson = {
3012
3013
  name: name,
3013
3014
  type: type,
@@ -4685,28 +4686,40 @@ class SearchService {
4685
4686
  __publicField$1(this, "storage");
4686
4687
  this.storage = storage;
4687
4688
  }
4689
+ // Экранирование специальных символов регулярных выражений
4690
+ escapeRegex(text) {
4691
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4692
+ }
4688
4693
  async search(query) {
4689
4694
  if (!query || query.trim().length === 0) {
4690
4695
  return [];
4691
4696
  }
4692
4697
  const results = [];
4693
4698
  const trimmedQuery = query.trim();
4694
- const regex = new RegExp(trimmedQuery, "i");
4699
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u043F\u043E \u0437\u0430\u043F\u0440\u043E\u0441\u0443: "${trimmedQuery}"`);
4700
+ const escapedQuery = this.escapeRegex(trimmedQuery);
4695
4701
  const queryWords = trimmedQuery.split(/\s+/).filter((word) => word.length > 0);
4696
4702
  try {
4697
- const individualResults = await this.searchIndividuals(regex, queryWords);
4703
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u0432 individuals...`);
4704
+ const individualResults = await this.searchIndividuals(escapedQuery, queryWords, trimmedQuery);
4705
+ console.log(`[SearchService] \u041D\u0430\u0439\u0434\u0435\u043D\u043E individuals: ${individualResults.length}`);
4698
4706
  results.push(...individualResults);
4699
- const entrepreneurResults = await this.searchEntrepreneurs(regex, queryWords);
4707
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u0432 entrepreneurs...`);
4708
+ const entrepreneurResults = await this.searchEntrepreneurs(escapedQuery, queryWords, trimmedQuery);
4709
+ console.log(`[SearchService] \u041D\u0430\u0439\u0434\u0435\u043D\u043E entrepreneurs: ${entrepreneurResults.length}`);
4700
4710
  results.push(...entrepreneurResults);
4701
- const organizationResults = await this.searchOrganizations(regex);
4711
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u0432 organizations...`);
4712
+ const organizationResults = await this.searchOrganizations(escapedQuery);
4713
+ console.log(`[SearchService] \u041D\u0430\u0439\u0434\u0435\u043D\u043E organizations: ${organizationResults.length}`);
4702
4714
  results.push(...organizationResults);
4715
+ console.log(`[SearchService] \u041E\u0431\u0449\u0435\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u043E\u0432: ${results.length}`);
4703
4716
  return results.slice(0, 10);
4704
4717
  } catch (error) {
4705
- console.error("Error during search:", error);
4718
+ console.error("[SearchService] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0438\u0441\u043A\u0435:", error);
4706
4719
  return [];
4707
4720
  }
4708
4721
  }
4709
- async searchIndividuals(regex, queryWords) {
4722
+ async searchIndividuals(regexPattern, queryWords, originalQuery) {
4710
4723
  const individualModel = new Individual(this.storage);
4711
4724
  const results = [];
4712
4725
  let filter;
@@ -4715,16 +4728,16 @@ class SearchService {
4715
4728
  deleted: false,
4716
4729
  $or: [
4717
4730
  // Поиск по отдельным полям
4718
- { first_name: { $regex: regex } },
4719
- { last_name: { $regex: regex } },
4720
- { middle_name: { $regex: regex } },
4731
+ { first_name: { $regex: regexPattern, $options: "i" } },
4732
+ { last_name: { $regex: regexPattern, $options: "i" } },
4733
+ { middle_name: { $regex: regexPattern, $options: "i" } },
4721
4734
  // Поиск по полному ФИО (все слова должны быть найдены)
4722
4735
  {
4723
4736
  $and: queryWords.map((word) => ({
4724
4737
  $or: [
4725
- { first_name: { $regex: new RegExp(word, "i") } },
4726
- { last_name: { $regex: new RegExp(word, "i") } },
4727
- { middle_name: { $regex: new RegExp(word, "i") } }
4738
+ { first_name: { $regex: this.escapeRegex(word), $options: "i" } },
4739
+ { last_name: { $regex: this.escapeRegex(word), $options: "i" } },
4740
+ { middle_name: { $regex: this.escapeRegex(word), $options: "i" } }
4728
4741
  ]
4729
4742
  }))
4730
4743
  }
@@ -4734,22 +4747,30 @@ class SearchService {
4734
4747
  filter = {
4735
4748
  deleted: false,
4736
4749
  $or: [
4737
- { first_name: { $regex: regex } },
4738
- { last_name: { $regex: regex } },
4739
- { middle_name: { $regex: regex } }
4750
+ { first_name: { $regex: regexPattern, $options: "i" } },
4751
+ { last_name: { $regex: regexPattern, $options: "i" } },
4752
+ { middle_name: { $regex: regexPattern, $options: "i" } }
4740
4753
  ]
4741
4754
  };
4742
4755
  }
4756
+ console.log(`[SearchService] \u0424\u0438\u043B\u044C\u0442\u0440 \u0434\u043B\u044F individuals:`, JSON.stringify(filter, null, 2));
4743
4757
  const individuals = await individualModel.getMany(filter);
4758
+ console.log(`[SearchService] \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B \u043F\u043E\u0438\u0441\u043A\u0430 individuals:`, {
4759
+ total: individuals.totalResults,
4760
+ found: individuals.results.length,
4761
+ query: originalQuery,
4762
+ names: individuals.results.map((ind) => `${ind.last_name} ${ind.first_name} ${ind.middle_name || ""} (deleted: ${ind.deleted || false})`)
4763
+ });
4744
4764
  for (const individual of individuals.results) {
4745
4765
  const highlightedFields = [];
4746
- if (regex.test(individual.first_name))
4766
+ const testRegex = new RegExp(regexPattern, "i");
4767
+ if (individual.first_name && testRegex.test(individual.first_name))
4747
4768
  highlightedFields.push("first_name");
4748
- if (regex.test(individual.last_name))
4769
+ if (individual.last_name && testRegex.test(individual.last_name))
4749
4770
  highlightedFields.push("last_name");
4750
- if (regex.test(individual.middle_name))
4771
+ if (individual.middle_name && testRegex.test(individual.middle_name))
4751
4772
  highlightedFields.push("middle_name");
4752
- const fullName = `${individual.last_name} ${individual.first_name} ${individual.middle_name}`.trim();
4773
+ const fullName = `${individual.last_name || ""} ${individual.first_name || ""} ${individual.middle_name || ""}`.trim();
4753
4774
  if (this.matchesFullName(fullName, queryWords)) {
4754
4775
  highlightedFields.push("full_name");
4755
4776
  }
@@ -4761,7 +4782,7 @@ class SearchService {
4761
4782
  }
4762
4783
  return results;
4763
4784
  }
4764
- async searchEntrepreneurs(regex, queryWords) {
4785
+ async searchEntrepreneurs(regexPattern, queryWords, originalQuery) {
4765
4786
  const entrepreneurModel = new Entrepreneur(this.storage);
4766
4787
  const results = [];
4767
4788
  let filter;
@@ -4770,18 +4791,18 @@ class SearchService {
4770
4791
  deleted: false,
4771
4792
  $or: [
4772
4793
  // Поиск по отдельным полям
4773
- { first_name: { $regex: regex } },
4774
- { last_name: { $regex: regex } },
4775
- { middle_name: { $regex: regex } },
4776
- { "details.inn": { $regex: regex } },
4777
- { "details.ogrn": { $regex: regex } },
4794
+ { first_name: { $regex: regexPattern, $options: "i" } },
4795
+ { last_name: { $regex: regexPattern, $options: "i" } },
4796
+ { middle_name: { $regex: regexPattern, $options: "i" } },
4797
+ { "details.inn": { $regex: regexPattern, $options: "i" } },
4798
+ { "details.ogrn": { $regex: regexPattern, $options: "i" } },
4778
4799
  // Поиск по полному ФИО
4779
4800
  {
4780
4801
  $and: queryWords.map((word) => ({
4781
4802
  $or: [
4782
- { first_name: { $regex: new RegExp(word, "i") } },
4783
- { last_name: { $regex: new RegExp(word, "i") } },
4784
- { middle_name: { $regex: new RegExp(word, "i") } }
4803
+ { first_name: { $regex: this.escapeRegex(word), $options: "i" } },
4804
+ { last_name: { $regex: this.escapeRegex(word), $options: "i" } },
4805
+ { middle_name: { $regex: this.escapeRegex(word), $options: "i" } }
4785
4806
  ]
4786
4807
  }))
4787
4808
  }
@@ -4791,28 +4812,36 @@ class SearchService {
4791
4812
  filter = {
4792
4813
  deleted: false,
4793
4814
  $or: [
4794
- { first_name: { $regex: regex } },
4795
- { last_name: { $regex: regex } },
4796
- { middle_name: { $regex: regex } },
4797
- { "details.inn": { $regex: regex } },
4798
- { "details.ogrn": { $regex: regex } }
4815
+ { first_name: { $regex: regexPattern, $options: "i" } },
4816
+ { last_name: { $regex: regexPattern, $options: "i" } },
4817
+ { middle_name: { $regex: regexPattern, $options: "i" } },
4818
+ { "details.inn": { $regex: regexPattern, $options: "i" } },
4819
+ { "details.ogrn": { $regex: regexPattern, $options: "i" } }
4799
4820
  ]
4800
4821
  };
4801
4822
  }
4823
+ console.log(`[SearchService] \u0424\u0438\u043B\u044C\u0442\u0440 \u0434\u043B\u044F entrepreneurs:`, JSON.stringify(filter, null, 2));
4802
4824
  const entrepreneurs = await entrepreneurModel.getMany(filter);
4825
+ console.log(`[SearchService] \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B \u043F\u043E\u0438\u0441\u043A\u0430 entrepreneurs:`, {
4826
+ total: entrepreneurs.totalResults,
4827
+ found: entrepreneurs.results.length,
4828
+ query: originalQuery,
4829
+ names: entrepreneurs.results.map((ent) => `${ent.last_name} ${ent.first_name} ${ent.middle_name || ""} (deleted: ${ent.deleted || false})`)
4830
+ });
4803
4831
  for (const entrepreneur of entrepreneurs.results) {
4804
4832
  const highlightedFields = [];
4805
- if (regex.test(entrepreneur.first_name))
4833
+ const testRegex = new RegExp(regexPattern, "i");
4834
+ if (entrepreneur.first_name && testRegex.test(entrepreneur.first_name))
4806
4835
  highlightedFields.push("first_name");
4807
- if (regex.test(entrepreneur.last_name))
4836
+ if (entrepreneur.last_name && testRegex.test(entrepreneur.last_name))
4808
4837
  highlightedFields.push("last_name");
4809
- if (regex.test(entrepreneur.middle_name))
4838
+ if (entrepreneur.middle_name && testRegex.test(entrepreneur.middle_name))
4810
4839
  highlightedFields.push("middle_name");
4811
- if (entrepreneur.details?.inn && regex.test(entrepreneur.details.inn))
4840
+ if (entrepreneur.details?.inn && testRegex.test(entrepreneur.details.inn))
4812
4841
  highlightedFields.push("details.inn");
4813
- if (entrepreneur.details?.ogrn && regex.test(entrepreneur.details.ogrn))
4842
+ if (entrepreneur.details?.ogrn && testRegex.test(entrepreneur.details.ogrn))
4814
4843
  highlightedFields.push("details.ogrn");
4815
- const fullName = `${entrepreneur.last_name} ${entrepreneur.first_name} ${entrepreneur.middle_name}`.trim();
4844
+ const fullName = `${entrepreneur.last_name || ""} ${entrepreneur.first_name || ""} ${entrepreneur.middle_name || ""}`.trim();
4816
4845
  if (this.matchesFullName(fullName, queryWords)) {
4817
4846
  highlightedFields.push("full_name");
4818
4847
  }
@@ -4824,24 +4853,25 @@ class SearchService {
4824
4853
  }
4825
4854
  return results;
4826
4855
  }
4827
- async searchOrganizations(regex) {
4856
+ async searchOrganizations(regexPattern) {
4828
4857
  const organizationModel = new Organization(this.storage);
4829
4858
  const results = [];
4830
4859
  const organizations = await organizationModel.getMany({
4831
4860
  deleted: false,
4832
4861
  $or: [
4833
- { short_name: { $regex: regex } },
4834
- { "details.inn": { $regex: regex } },
4835
- { "details.ogrn": { $regex: regex } }
4862
+ { short_name: { $regex: regexPattern, $options: "i" } },
4863
+ { "details.inn": { $regex: regexPattern, $options: "i" } },
4864
+ { "details.ogrn": { $regex: regexPattern, $options: "i" } }
4836
4865
  ]
4837
4866
  });
4838
4867
  for (const organization of organizations.results) {
4839
4868
  const highlightedFields = [];
4840
- if (regex.test(organization.short_name))
4869
+ const testRegex = new RegExp(regexPattern, "i");
4870
+ if (testRegex.test(organization.short_name))
4841
4871
  highlightedFields.push("short_name");
4842
- if (organization.details?.inn && regex.test(organization.details.inn))
4872
+ if (organization.details?.inn && testRegex.test(organization.details.inn))
4843
4873
  highlightedFields.push("details.inn");
4844
- if (organization.details?.ogrn && regex.test(organization.details.ogrn))
4874
+ if (organization.details?.ogrn && testRegex.test(organization.details.ogrn))
4845
4875
  highlightedFields.push("details.ogrn");
4846
4876
  results.push({
4847
4877
  type: "organization",
package/dist/index.mjs CHANGED
@@ -2903,7 +2903,7 @@ class PDFService {
2903
2903
 
2904
2904
  const name = "@coopenomics/factory";
2905
2905
  const type = "module";
2906
- const version = "2025.7.1";
2906
+ const version = "2025.7.2";
2907
2907
  const packageManager = "pnpm@9.0.6";
2908
2908
  const description = "";
2909
2909
  const author = "Alex Ant <chairman.voskhod@gmail.com>";
@@ -2946,14 +2946,15 @@ const scripts = {
2946
2946
  prepublishOnly: "nr build",
2947
2947
  release: "bumpp && npm publish",
2948
2948
  test: "vitest --dir test --testTimeout=240000 --exclude documents --watch=false",
2949
- typecheck: "tsc --noEmit"
2949
+ typecheck: "tsc --noEmit",
2950
+ "setup-indexes": "tsx scripts/setup-indexes.ts"
2950
2951
  };
2951
2952
  const dependencies = {
2952
2953
  ajv: "^8.13.0",
2953
2954
  "ajv-formats": "^3.0.1",
2954
2955
  "ajv-i18n": "^4.2.0",
2955
2956
  axios: "^1.7.2",
2956
- cooptypes: "2025.7.1",
2957
+ cooptypes: "2025.7.2",
2957
2958
  dotenv: "^16.4.5",
2958
2959
  "eosjs-ecc": "^4.0.7",
2959
2960
  handlebars: "^4.7.8",
@@ -2994,7 +2995,7 @@ const pnpm = {
2994
2995
  "vite@>=5.1.0 <=5.1.6": ">=5.1.7"
2995
2996
  }
2996
2997
  };
2997
- const gitHead = "ac8836628eb82672b481dbf86050918f41bf24ca";
2998
+ const gitHead = "305864c1ed125be304a3b4fa9749ac6743dd5571";
2998
2999
  const packageJson = {
2999
3000
  name: name,
3000
3001
  type: type,
@@ -4672,28 +4673,40 @@ class SearchService {
4672
4673
  __publicField$1(this, "storage");
4673
4674
  this.storage = storage;
4674
4675
  }
4676
+ // Экранирование специальных символов регулярных выражений
4677
+ escapeRegex(text) {
4678
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4679
+ }
4675
4680
  async search(query) {
4676
4681
  if (!query || query.trim().length === 0) {
4677
4682
  return [];
4678
4683
  }
4679
4684
  const results = [];
4680
4685
  const trimmedQuery = query.trim();
4681
- const regex = new RegExp(trimmedQuery, "i");
4686
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u043F\u043E \u0437\u0430\u043F\u0440\u043E\u0441\u0443: "${trimmedQuery}"`);
4687
+ const escapedQuery = this.escapeRegex(trimmedQuery);
4682
4688
  const queryWords = trimmedQuery.split(/\s+/).filter((word) => word.length > 0);
4683
4689
  try {
4684
- const individualResults = await this.searchIndividuals(regex, queryWords);
4690
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u0432 individuals...`);
4691
+ const individualResults = await this.searchIndividuals(escapedQuery, queryWords, trimmedQuery);
4692
+ console.log(`[SearchService] \u041D\u0430\u0439\u0434\u0435\u043D\u043E individuals: ${individualResults.length}`);
4685
4693
  results.push(...individualResults);
4686
- const entrepreneurResults = await this.searchEntrepreneurs(regex, queryWords);
4694
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u0432 entrepreneurs...`);
4695
+ const entrepreneurResults = await this.searchEntrepreneurs(escapedQuery, queryWords, trimmedQuery);
4696
+ console.log(`[SearchService] \u041D\u0430\u0439\u0434\u0435\u043D\u043E entrepreneurs: ${entrepreneurResults.length}`);
4687
4697
  results.push(...entrepreneurResults);
4688
- const organizationResults = await this.searchOrganizations(regex);
4698
+ console.log(`[SearchService] \u041F\u043E\u0438\u0441\u043A \u0432 organizations...`);
4699
+ const organizationResults = await this.searchOrganizations(escapedQuery);
4700
+ console.log(`[SearchService] \u041D\u0430\u0439\u0434\u0435\u043D\u043E organizations: ${organizationResults.length}`);
4689
4701
  results.push(...organizationResults);
4702
+ console.log(`[SearchService] \u041E\u0431\u0449\u0435\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u043E\u0432: ${results.length}`);
4690
4703
  return results.slice(0, 10);
4691
4704
  } catch (error) {
4692
- console.error("Error during search:", error);
4705
+ console.error("[SearchService] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0438\u0441\u043A\u0435:", error);
4693
4706
  return [];
4694
4707
  }
4695
4708
  }
4696
- async searchIndividuals(regex, queryWords) {
4709
+ async searchIndividuals(regexPattern, queryWords, originalQuery) {
4697
4710
  const individualModel = new Individual(this.storage);
4698
4711
  const results = [];
4699
4712
  let filter;
@@ -4702,16 +4715,16 @@ class SearchService {
4702
4715
  deleted: false,
4703
4716
  $or: [
4704
4717
  // Поиск по отдельным полям
4705
- { first_name: { $regex: regex } },
4706
- { last_name: { $regex: regex } },
4707
- { middle_name: { $regex: regex } },
4718
+ { first_name: { $regex: regexPattern, $options: "i" } },
4719
+ { last_name: { $regex: regexPattern, $options: "i" } },
4720
+ { middle_name: { $regex: regexPattern, $options: "i" } },
4708
4721
  // Поиск по полному ФИО (все слова должны быть найдены)
4709
4722
  {
4710
4723
  $and: queryWords.map((word) => ({
4711
4724
  $or: [
4712
- { first_name: { $regex: new RegExp(word, "i") } },
4713
- { last_name: { $regex: new RegExp(word, "i") } },
4714
- { middle_name: { $regex: new RegExp(word, "i") } }
4725
+ { first_name: { $regex: this.escapeRegex(word), $options: "i" } },
4726
+ { last_name: { $regex: this.escapeRegex(word), $options: "i" } },
4727
+ { middle_name: { $regex: this.escapeRegex(word), $options: "i" } }
4715
4728
  ]
4716
4729
  }))
4717
4730
  }
@@ -4721,22 +4734,30 @@ class SearchService {
4721
4734
  filter = {
4722
4735
  deleted: false,
4723
4736
  $or: [
4724
- { first_name: { $regex: regex } },
4725
- { last_name: { $regex: regex } },
4726
- { middle_name: { $regex: regex } }
4737
+ { first_name: { $regex: regexPattern, $options: "i" } },
4738
+ { last_name: { $regex: regexPattern, $options: "i" } },
4739
+ { middle_name: { $regex: regexPattern, $options: "i" } }
4727
4740
  ]
4728
4741
  };
4729
4742
  }
4743
+ console.log(`[SearchService] \u0424\u0438\u043B\u044C\u0442\u0440 \u0434\u043B\u044F individuals:`, JSON.stringify(filter, null, 2));
4730
4744
  const individuals = await individualModel.getMany(filter);
4745
+ console.log(`[SearchService] \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B \u043F\u043E\u0438\u0441\u043A\u0430 individuals:`, {
4746
+ total: individuals.totalResults,
4747
+ found: individuals.results.length,
4748
+ query: originalQuery,
4749
+ names: individuals.results.map((ind) => `${ind.last_name} ${ind.first_name} ${ind.middle_name || ""} (deleted: ${ind.deleted || false})`)
4750
+ });
4731
4751
  for (const individual of individuals.results) {
4732
4752
  const highlightedFields = [];
4733
- if (regex.test(individual.first_name))
4753
+ const testRegex = new RegExp(regexPattern, "i");
4754
+ if (individual.first_name && testRegex.test(individual.first_name))
4734
4755
  highlightedFields.push("first_name");
4735
- if (regex.test(individual.last_name))
4756
+ if (individual.last_name && testRegex.test(individual.last_name))
4736
4757
  highlightedFields.push("last_name");
4737
- if (regex.test(individual.middle_name))
4758
+ if (individual.middle_name && testRegex.test(individual.middle_name))
4738
4759
  highlightedFields.push("middle_name");
4739
- const fullName = `${individual.last_name} ${individual.first_name} ${individual.middle_name}`.trim();
4760
+ const fullName = `${individual.last_name || ""} ${individual.first_name || ""} ${individual.middle_name || ""}`.trim();
4740
4761
  if (this.matchesFullName(fullName, queryWords)) {
4741
4762
  highlightedFields.push("full_name");
4742
4763
  }
@@ -4748,7 +4769,7 @@ class SearchService {
4748
4769
  }
4749
4770
  return results;
4750
4771
  }
4751
- async searchEntrepreneurs(regex, queryWords) {
4772
+ async searchEntrepreneurs(regexPattern, queryWords, originalQuery) {
4752
4773
  const entrepreneurModel = new Entrepreneur(this.storage);
4753
4774
  const results = [];
4754
4775
  let filter;
@@ -4757,18 +4778,18 @@ class SearchService {
4757
4778
  deleted: false,
4758
4779
  $or: [
4759
4780
  // Поиск по отдельным полям
4760
- { first_name: { $regex: regex } },
4761
- { last_name: { $regex: regex } },
4762
- { middle_name: { $regex: regex } },
4763
- { "details.inn": { $regex: regex } },
4764
- { "details.ogrn": { $regex: regex } },
4781
+ { first_name: { $regex: regexPattern, $options: "i" } },
4782
+ { last_name: { $regex: regexPattern, $options: "i" } },
4783
+ { middle_name: { $regex: regexPattern, $options: "i" } },
4784
+ { "details.inn": { $regex: regexPattern, $options: "i" } },
4785
+ { "details.ogrn": { $regex: regexPattern, $options: "i" } },
4765
4786
  // Поиск по полному ФИО
4766
4787
  {
4767
4788
  $and: queryWords.map((word) => ({
4768
4789
  $or: [
4769
- { first_name: { $regex: new RegExp(word, "i") } },
4770
- { last_name: { $regex: new RegExp(word, "i") } },
4771
- { middle_name: { $regex: new RegExp(word, "i") } }
4790
+ { first_name: { $regex: this.escapeRegex(word), $options: "i" } },
4791
+ { last_name: { $regex: this.escapeRegex(word), $options: "i" } },
4792
+ { middle_name: { $regex: this.escapeRegex(word), $options: "i" } }
4772
4793
  ]
4773
4794
  }))
4774
4795
  }
@@ -4778,28 +4799,36 @@ class SearchService {
4778
4799
  filter = {
4779
4800
  deleted: false,
4780
4801
  $or: [
4781
- { first_name: { $regex: regex } },
4782
- { last_name: { $regex: regex } },
4783
- { middle_name: { $regex: regex } },
4784
- { "details.inn": { $regex: regex } },
4785
- { "details.ogrn": { $regex: regex } }
4802
+ { first_name: { $regex: regexPattern, $options: "i" } },
4803
+ { last_name: { $regex: regexPattern, $options: "i" } },
4804
+ { middle_name: { $regex: regexPattern, $options: "i" } },
4805
+ { "details.inn": { $regex: regexPattern, $options: "i" } },
4806
+ { "details.ogrn": { $regex: regexPattern, $options: "i" } }
4786
4807
  ]
4787
4808
  };
4788
4809
  }
4810
+ console.log(`[SearchService] \u0424\u0438\u043B\u044C\u0442\u0440 \u0434\u043B\u044F entrepreneurs:`, JSON.stringify(filter, null, 2));
4789
4811
  const entrepreneurs = await entrepreneurModel.getMany(filter);
4812
+ console.log(`[SearchService] \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B \u043F\u043E\u0438\u0441\u043A\u0430 entrepreneurs:`, {
4813
+ total: entrepreneurs.totalResults,
4814
+ found: entrepreneurs.results.length,
4815
+ query: originalQuery,
4816
+ names: entrepreneurs.results.map((ent) => `${ent.last_name} ${ent.first_name} ${ent.middle_name || ""} (deleted: ${ent.deleted || false})`)
4817
+ });
4790
4818
  for (const entrepreneur of entrepreneurs.results) {
4791
4819
  const highlightedFields = [];
4792
- if (regex.test(entrepreneur.first_name))
4820
+ const testRegex = new RegExp(regexPattern, "i");
4821
+ if (entrepreneur.first_name && testRegex.test(entrepreneur.first_name))
4793
4822
  highlightedFields.push("first_name");
4794
- if (regex.test(entrepreneur.last_name))
4823
+ if (entrepreneur.last_name && testRegex.test(entrepreneur.last_name))
4795
4824
  highlightedFields.push("last_name");
4796
- if (regex.test(entrepreneur.middle_name))
4825
+ if (entrepreneur.middle_name && testRegex.test(entrepreneur.middle_name))
4797
4826
  highlightedFields.push("middle_name");
4798
- if (entrepreneur.details?.inn && regex.test(entrepreneur.details.inn))
4827
+ if (entrepreneur.details?.inn && testRegex.test(entrepreneur.details.inn))
4799
4828
  highlightedFields.push("details.inn");
4800
- if (entrepreneur.details?.ogrn && regex.test(entrepreneur.details.ogrn))
4829
+ if (entrepreneur.details?.ogrn && testRegex.test(entrepreneur.details.ogrn))
4801
4830
  highlightedFields.push("details.ogrn");
4802
- const fullName = `${entrepreneur.last_name} ${entrepreneur.first_name} ${entrepreneur.middle_name}`.trim();
4831
+ const fullName = `${entrepreneur.last_name || ""} ${entrepreneur.first_name || ""} ${entrepreneur.middle_name || ""}`.trim();
4803
4832
  if (this.matchesFullName(fullName, queryWords)) {
4804
4833
  highlightedFields.push("full_name");
4805
4834
  }
@@ -4811,24 +4840,25 @@ class SearchService {
4811
4840
  }
4812
4841
  return results;
4813
4842
  }
4814
- async searchOrganizations(regex) {
4843
+ async searchOrganizations(regexPattern) {
4815
4844
  const organizationModel = new Organization(this.storage);
4816
4845
  const results = [];
4817
4846
  const organizations = await organizationModel.getMany({
4818
4847
  deleted: false,
4819
4848
  $or: [
4820
- { short_name: { $regex: regex } },
4821
- { "details.inn": { $regex: regex } },
4822
- { "details.ogrn": { $regex: regex } }
4849
+ { short_name: { $regex: regexPattern, $options: "i" } },
4850
+ { "details.inn": { $regex: regexPattern, $options: "i" } },
4851
+ { "details.ogrn": { $regex: regexPattern, $options: "i" } }
4823
4852
  ]
4824
4853
  });
4825
4854
  for (const organization of organizations.results) {
4826
4855
  const highlightedFields = [];
4827
- if (regex.test(organization.short_name))
4856
+ const testRegex = new RegExp(regexPattern, "i");
4857
+ if (testRegex.test(organization.short_name))
4828
4858
  highlightedFields.push("short_name");
4829
- if (organization.details?.inn && regex.test(organization.details.inn))
4859
+ if (organization.details?.inn && testRegex.test(organization.details.inn))
4830
4860
  highlightedFields.push("details.inn");
4831
- if (organization.details?.ogrn && regex.test(organization.details.ogrn))
4861
+ if (organization.details?.ogrn && testRegex.test(organization.details.ogrn))
4832
4862
  highlightedFields.push("details.ogrn");
4833
4863
  results.push({
4834
4864
  type: "organization",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coopenomics/factory",
3
3
  "type": "module",
4
- "version": "2025.7.1",
4
+ "version": "2025.7.2",
5
5
  "packageManager": "pnpm@9.0.6",
6
6
  "description": "",
7
7
  "author": "Alex Ant <chairman.voskhod@gmail.com>",
@@ -43,14 +43,15 @@
43
43
  "prepublishOnly": "nr build",
44
44
  "release": "bumpp && npm publish",
45
45
  "test": "vitest --dir test --testTimeout=240000 --exclude documents --watch=false",
46
- "typecheck": "tsc --noEmit"
46
+ "typecheck": "tsc --noEmit",
47
+ "setup-indexes": "tsx scripts/setup-indexes.ts"
47
48
  },
48
49
  "dependencies": {
49
50
  "ajv": "^8.13.0",
50
51
  "ajv-formats": "^3.0.1",
51
52
  "ajv-i18n": "^4.2.0",
52
53
  "axios": "^1.7.2",
53
- "cooptypes": "2025.7.1",
54
+ "cooptypes": "2025.7.2",
54
55
  "dotenv": "^16.4.5",
55
56
  "eosjs-ecc": "^4.0.7",
56
57
  "handlebars": "^4.7.8",
@@ -91,5 +92,5 @@
91
92
  "vite@>=5.1.0 <=5.1.6": ">=5.1.7"
92
93
  }
93
94
  },
94
- "gitHead": "ac8836628eb82672b481dbf86050918f41bf24ca"
95
+ "gitHead": "305864c1ed125be304a3b4fa9749ac6743dd5571"
95
96
  }